snibgo's ImageMagick pages

New FX tests

Tests for a proposed faster "-fx".

This page shows black-box tests performed on a new version of "-fx", comparing results to an old version of "-fx".

The tests were performed on my Windows 10 laptop. The CPU (Intel Core i7-4700MQ @2.40GHz) has 4 cores, and can run 8 threads. The IM version was v7.1.0-20, Q32, with HDRI and OpenMP. Two builds were created, for the old and new "-fx", and installed in the directories "%FXOLD%" and "%FXNEW%".

These tests are not exhaustive. I welcome any additions.

This is a companion page to New FX.

Performance

The script testPerf.bat runs a magick command for the old fx, and repeats it for the new fx. The command runs a "-fx" operation for each of the input strings in testPerf.txt. There are about 35 input strings.

Input size, pixels Old "-fx" New "-fx2"
10x10 2 second 2 seconds
100x10 4 seconds 2 seconds
100x100 14 seconds 2 seconds
1000x100 99 seconds 4 seconds
1000x1000 ???? seconds 9 seconds

Compatibility and accuracy

To test compatiblity, we run the same "-fx" operation using the old and new fx code, and find the RMSE distortion between the two results. The distortion is on a nominal scale of zero to one. If it is very close to zero, we consider the test has passed.

For accuracy, the results were compared to hand-calculations.

call %IM7SRC%\snibgo\goodFxSyntax.bat

Tests with a single input image:

-fx input string distortion
'0.000023M' 0
'10 - 2 + 3' 0
'10 * 2 + 3' 0
'4 ^ 3 ^ 2' 0
'0.3 ^ 1.5 ^ 2' 0
'xx=1? xx:4' 0
'-epsilon' 0
'3-1 ? 4+5 : 6 ? 7 :2*3' 0
'yy = 3-1 ? 4+5 : 6 ? 7 :2*3' 0
'aa=56; yy = 3-3 ? 4+5 : 6 ? 2+aa+3 :2*3' 0
'23+(+1)' 0
'23+(-1)' 0
'xx=23;-xx' 0
'xx=23;-(xx+1)' 0
'xx=23;-xx+1' 0
'xx=23;xx-=2;xx' 0
'xx=23; yy=34; xx+yy' 0
'xx = yy = 2+3' 0
'if (1,2,3)' 0
'if (1,2,)' 0
'if (1,,3)' 0
'u<0.01 ? 1: u>0.99 ? 0: u' 0
'if (u<0.01, 1, if (u>0.99, 0, u))' 0
'mean' 0
'mean.r' 0
'u.mean' 0
'u.mean.r' 0
'#abd' 0
'hsl(10%,20%,30%)' 0
'u.saturation' 0
'10 < i < 12' 0
'(0.10 < i) && (i < 0.12)' 0
'gray47' 0
'r - gray47' 0
'1/2' 0
'(1.0/(1.0+exp(10.0*(0.5-u)))-0.006693)*1.0092503' 0
'Xi=i-w/2; Yj=j-h/2; 1.2*(0.5-hypot(Xi,Yj)/70.0)+0.5' 0
'for (prime=2, prime < 30, composite=0; for (nn=2, nn < (prime/2+1), if ((prime % nn) == 0, composite++, ); nn++); if (composite <= 0, debug(prime), ); prime++)' 0

Tests with two input images:

-fx input string distortion
'u' 0
'v' 0
's' 0
'u[1]' 0
'u.g' 0
'v.g' 0
's.g' 0
'u[1].g' 0
'mean' 0
'u.mean' 0
'v.mean' 0
's.mean' 0
'u[1].mean' 0
'mean.g' 0
'v.mean.g' 0
'u[1]mean.g' 0
'u.p{2,3}' 0
'u.p[2,3]' 0
'u.p{2,3}.g' 0
'u.p[2,3].g' 0
'v.p{2,3}' 0
'v.p[2,3]' 0
'v.p{2,3}.g' 0
'v.p[2,3].g' 0
'u[1].p{2,3}' 0
'u[1].p[2,3]' 0
'u[1].p{2,3}.g' 0
'u[1].p[2,3].g' 0
's.p{2,3}' 0
's.p[2,3]' 0
's.p{2,3}.g' 0
's.p[2,3].g' 0
'u.saturation' 0
'v.saturation' 0
's.saturation' 0
'u[1].saturation' 0
'u.p[1,2].saturation' 0
'v.p[1,2].saturation' 0
's.p[1,2].saturation' 0
'u[1].p[1,2].saturation' 0
'u-v+0.5' 0

Tests that fail (they show significant differences):

-fx input string distortion
'2300m' 2.3
'23 ;' 23
'23+(++1)' 1
'23+(--1)' 1
'xx=23;--xx' 23
'xx=23;--xx+1' 23
'xx=3; yy=xx++; yy' 3
'iso=32; rone=rand(); rtwo=rand(); myn=sqrt(-2*ln(rone))*cos(2*Pi*rtwo); myntwo=sqrt(-2*ln(rtwo))* cos(2*Pi*rone); pnoise=sqrt(p)*myn*sqrt(iso)* channel(4.28,3.86,6.68,0)/255; max(0,p+pnoise)' 2.24039

"2300m" has an SI prefix meaning "multiplied by 10-3", and the negative power doesn't work in the old "-fx".

"23 ;" shows different processing of the blank statement after the semi-colon. The old "-fx" returns 0 from blank statements. In the new "-fx", blank statements have no effect, so the return is whatever the previous statement returned.

Expressions with "rand()" give different results each time.

The old "-fx" has a problem with multiple unary prefixes:

%FXOLD%magick xc: -fx "23+(--2.5)" txt: 
%FXNEW%magick xc: -fx "23+(--2.5)" txt: 
# ImageMagick pixel enumeration: 1,1,4294967295,srgb
0,0: (9.8784248e+10,9.8784248e+10,9.8784248e+10)  #FFFFFFFFFFFFFFFFFFFFFFFF  srgb(2300%,2300%,2300%)
# ImageMagick pixel enumeration: 1,1,4294967295,srgb
0,0: (1.0952167e+11,1.0952167e+11,1.0952167e+11)  #FFFFFFFFFFFFFFFFFFFFFFFF  srgb(2550%,2550%,2550%)

I regard the new result to be correct.

For "xx=3; yy=xx++; yy", the old "-fx" returns zero. This is because it doesn't return a value from "xx++", but doesn't report a syntax problem and instead returns zero, which is used to set yy.

Sample formats

The script fmtTst.bat tests "-format %[string]" for the strings shown, for the old and new "-fx". It shows "same" when the outputs are identical, or "DIFFERENT" when they are different.

call %IM7SRC%\snibgo\fmtTst.bat

"-format %[fx:string]" using pixel operands without channel qualifiers are different because, as explained at New FX, the old "%[fx:u]" etc give an intensity, and the new versions give the red channel.

format string old result new result same/different
"fx:u-1.23e-4" 0.72865807 0.72865807 0.66654367 0.66654367 DIFFERENT
"fx:u-1.23e-4*2" 0.72853507 0.72853507 0.66642067 0.66642067 DIFFERENT
"fx:u-gray47" 0.25819283 0.25819283 0.19607843 0.19607843 DIFFERENT
"fx:u-gray47*2" -0.2123954 -0.2123954 -0.2745098 -0.2745098 DIFFERENT
"fx:u" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:v" 0.342698 0.342698 0.4 0.4 DIFFERENT
"fx:s" 0.72878107 0.342698 0.66666667 0.4 DIFFERENT
"fx:u[0]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:u[1-1]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:u[1]" 0.342698 0.342698 0.4 0.4 DIFFERENT
"fx:u.p[0,0]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:v.p[0,0]" 0.342698 0.342698 0.4 0.4 DIFFERENT
"fx:s.p[0,0]" 0.72878107 0.342698 0.66666667 0.4 DIFFERENT
"fx:u[0].p[0,0]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:u[1-1].p[0,0]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:u[1].p[0,0]" 0.342698 0.342698 0.4 0.4 DIFFERENT

In cases where we don't have pixel operands without channel qualifiers, "-format %[fx:string]" give identical results.

format string old result new result same/different
"fx:1.23e-4" 0.000123 0.000123 0.000123 0.000123 same
"fx:1.23e-4*2" 0.000246 0.000246 0.000246 0.000246 same
"fx:gray47" 0.47058824 0.47058824 0.47058824 0.47058824 same
"fx:gray47*2" 0.94117647 0.94117647 0.94117647 0.94117647 same
"fx:u-1.23e-4" 0.72865807 0.72865807 0.66654367 0.66654367 DIFFERENT
"fx:u-1.23e-4*2" 0.72853507 0.72853507 0.66642067 0.66642067 DIFFERENT
"fx:u-gray47" 0.25819283 0.25819283 0.19607843 0.19607843 DIFFERENT
"fx:u-gray47*2" -0.2123954 -0.2123954 -0.2745098 -0.2745098 DIFFERENT
"fx:u" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:v" 0.342698 0.342698 0.4 0.4 DIFFERENT
"fx:s" 0.72878107 0.342698 0.66666667 0.4 DIFFERENT
"fx:u[0]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:u[1-1]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:u[1]" 0.342698 0.342698 0.4 0.4 DIFFERENT
"fx:u.p[0,0]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:v.p[0,0]" 0.342698 0.342698 0.4 0.4 DIFFERENT
"fx:s.p[0,0]" 0.72878107 0.342698 0.66666667 0.4 DIFFERENT
"fx:u[0].p[0,0]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:u[1-1].p[0,0]" 0.72878107 0.72878107 0.66666667 0.66666667 DIFFERENT
"fx:u[1].p[0,0]" 0.342698 0.342698 0.4 0.4 DIFFERENT
"fx:u.g" 0.73333333 0.73333333 0.73333333 0.73333333 same
"fx:v.g" 0.33333333 0.33333333 0.33333333 0.33333333 same
"fx:s.g" 0.73333333 0.33333333 0.73333333 0.33333333 same
"fx:u[0].g" 0.73333333 0.73333333 0.73333333 0.73333333 same
"fx:u[1-1].g" 0.73333333 0.73333333 0.73333333 0.73333333 same
"fx:u[1].g" 0.33333333 0.33333333 0.33333333 0.33333333 same
"fx:u.p[0,0].g" 0.73333333 0.73333333 0.73333333 0.73333333 same
"fx:v.p[0,0].g" 0.33333333 0.33333333 0.33333333 0.33333333 same
"fx:s.p[0,0].g" 0.73333333 0.33333333 0.73333333 0.33333333 same
"fx:u[0].p[0,0].g" 0.73333333 0.73333333 0.73333333 0.73333333 same
"fx:u[1-1].p[0,0].g" 0.73333333 0.73333333 0.73333333 0.73333333 same
"fx:u[1].p[0,0].g" 0.33333333 0.33333333 0.33333333 0.33333333 same
"fx:u.saturation" 0.42857143 0.42857143 0.42857143 0.42857143 same
"fx:v.saturation" 0.2 0.2 0.2 0.2 same
"fx:s.saturation" 0.42857143 0.2 0.42857143 0.2 same
"fx:u[0].saturation" 0.42857143 0.42857143 0.42857143 0.42857143 same
"fx:u[1-1].saturation" 0.42857143 0.42857143 0.42857143 0.42857143 same
"fx:u[1].saturation" 0.2 0.2 0.2 0.2 same
"fx:u.p[0,0].saturation" 0.42857143 0.42857143 0.42857143 0.42857143 same
"fx:v.p[0,0].saturation" 0.2 0.2 0.2 0.2 same
"fx:s.p[0,0].saturation" 0.42857143 0.2 0.42857143 0.2 same
"fx:u[0].p[0,0].saturation" 0.42857143 0.42857143 0.42857143 0.42857143 same
"fx:u[1-1].p[0,0].saturation" 0.42857143 0.42857143 0.42857143 0.42857143 same
"fx:u[1].p[0,0].saturation" 0.2 0.2 0.2 0.2 same
"fx:u.median" 0.75555556 0.75555556 0.75555556 0.75555556 same
"fx:v.median" 0.33333333 0.33333333 0.33333333 0.33333333 same
"fx:s.median" 0.75555556 0.33333333 0.75555556 0.33333333 same
"fx:u[0].median" 0.75555556 0.75555556 0.75555556 0.75555556 same
"fx:u[1-1].median" 0.75555556 0.75555556 0.75555556 0.75555556 same
"fx:u[1].median" 0.33333333 0.33333333 0.33333333 0.33333333 same

"-format %[hex:string]" are entirely the same.

format string old result new result same/different
"hex:1.23e-4" 00080F9900080F9900080F99 00080F9900080F9900080F99 00080F9900080F9900080F99 00080F9900080F9900080F99 same
"hex:1.23e-4*2" 00101F3200101F3200101F32 00101F3200101F3200101F32 00101F3200101F3200101F32 00101F3200101F3200101F32 same
"hex:gray47" 787878787878787878787878 787878787878787878787878 787878787878787878787878 787878787878787878787878 same
"hex:gray47*2" F0F0F0F0F0F0F0F0F0F0F0F0 F0F0F0F0F0F0F0F0F0F0F0F0 F0F0F0F0F0F0F0F0F0F0F0F0 F0F0F0F0F0F0F0F0F0F0F0F0 same
"hex:u-1.23e-4" AAA29B11BBB3AC22DDD5CE44 AAA29B11BBB3AC22DDD5CE44 AAA29B11BBB3AC22DDD5CE44 AAA29B11BBB3AC22DDD5CE44 same
"hex:u-1.23e-4*2" AA9A8B78BBAB9C89DDCDBEAB AA9A8B78BBAB9C89DDCDBEAB AA9A8B78BBAB9C89DDCDBEAB AA9A8B78BBAB9C89DDCDBEAB same
"hex:u-gray47" 323232324343434365656565 323232324343434365656565 323232324343434365656565 323232324343434365656565 same
"hex:u-gray47*2" 000000000000000000000000 000000000000000000000000 000000000000000000000000 000000000000000000000000 same
"hex:u" AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD same
"hex:v" 666666665555555544444444 666666665555555544444444 666666665555555544444444 666666665555555544444444 same
"hex:s" AAAAAAAABBBBBBBBDDDDDDDD 666666665555555544444444 AAAAAAAABBBBBBBBDDDDDDDD 666666665555555544444444 same
"hex:u[0]" AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD same
"hex:u[1-1]" AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD same
"hex:u[1]" 666666665555555544444444 666666665555555544444444 666666665555555544444444 666666665555555544444444 same
"hex:u.p[0,0]" AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD same
"hex:v.p[0,0]" 666666665555555544444444 666666665555555544444444 666666665555555544444444 666666665555555544444444 same
"hex:s.p[0,0]" AAAAAAAABBBBBBBBDDDDDDDD 666666665555555544444444 AAAAAAAABBBBBBBBDDDDDDDD 666666665555555544444444 same
"hex:u[0].p[0,0]" AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD same
"hex:u[1-1].p[0,0]" AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD AAAAAAAABBBBBBBBDDDDDDDD same
"hex:u[1].p[0,0]" 666666665555555544444444 666666665555555544444444 666666665555555544444444 666666665555555544444444 same
"hex:u.g" BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB same
"hex:v.g" 555555555555555555555555 555555555555555555555555 555555555555555555555555 555555555555555555555555 same
"hex:s.g" BBBBBBBBBBBBBBBBBBBBBBBB 555555555555555555555555 BBBBBBBBBBBBBBBBBBBBBBBB 555555555555555555555555 same
"hex:u[0].g" BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB same
"hex:u[1-1].g" BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB same
"hex:u[1].g" 555555555555555555555555 555555555555555555555555 555555555555555555555555 555555555555555555555555 same
"hex:u.p[0,0].g" BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB same
"hex:v.p[0,0].g" 555555555555555555555555 555555555555555555555555 555555555555555555555555 555555555555555555555555 same
"hex:s.p[0,0].g" BBBBBBBBBBBBBBBBBBBBBBBB 555555555555555555555555 BBBBBBBBBBBBBBBBBBBBBBBB 555555555555555555555555 same
"hex:u[0].p[0,0].g" BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB same
"hex:u[1-1].p[0,0].g" BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB same
"hex:u[1].p[0,0].g" 555555555555555555555555 555555555555555555555555 555555555555555555555555 555555555555555555555555 same
"hex:u.saturation" 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D same
"hex:v.saturation" 333333333333333333333333 333333333333333333333333 333333333333333333333333 333333333333333333333333 same
"hex:s.saturation" 6DB6DB6D6DB6DB6D6DB6DB6D 333333333333333333333333 6DB6DB6D6DB6DB6D6DB6DB6D 333333333333333333333333 same
"hex:u[0].saturation" 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D same
"hex:u[1-1].saturation" 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D same
"hex:u[1].saturation" 333333333333333333333333 333333333333333333333333 333333333333333333333333 333333333333333333333333 same
"hex:u.p[0,0].saturation" 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D same
"hex:v.p[0,0].saturation" 333333333333333333333333 333333333333333333333333 333333333333333333333333 333333333333333333333333 same
"hex:s.p[0,0].saturation" 6DB6DB6D6DB6DB6D6DB6DB6D 333333333333333333333333 6DB6DB6D6DB6DB6D6DB6DB6D 333333333333333333333333 same
"hex:u[0].p[0,0].saturation" 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D same
"hex:u[1-1].p[0,0].saturation" 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D 6DB6DB6D6DB6DB6D6DB6DB6D same
"hex:u[1].p[0,0].saturation" 333333333333333333333333 333333333333333333333333 333333333333333333333333 333333333333333333333333 same
"hex:u.median" C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 same
"hex:v.median" 555555555555555555555555 555555555555555555555555 555555555555555555555555 555555555555555555555555 same
"hex:s.median" C16C16C1C16C16C1C16C16C1 555555555555555555555555 C16C16C1C16C16C1C16C16C1 555555555555555555555555 same
"hex:u[0].median" C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 same
"hex:u[1-1].median" C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 C16C16C1C16C16C1C16C16C1 same
"hex:u[1].median" 555555555555555555555555 555555555555555555555555 555555555555555555555555 555555555555555555555555 same

"-format %[pixel:string]" are entirely the same.

format string old result new result same/different
"pixel:1.23e-4" srgb(0.012300001%,0.012300001%,0.012300001%) srgb(0.012300001%,0.012300001%,0.012300001%) srgb(0.012300001%,0.012300001%,0.012300001%) srgb(0.012300001%,0.012300001%,0.012300001%) same
"pixel:1.23e-4*2" srgb(0.024600001%,0.024600001%,0.024600001%) srgb(0.024600001%,0.024600001%,0.024600001%) srgb(0.024600001%,0.024600001%,0.024600001%) srgb(0.024600001%,0.024600001%,0.024600001%) same
"pixel:gray47" srgb(120,120,120) srgb(120,120,120) srgb(120,120,120) srgb(120,120,120) same
"pixel:gray47*2" srgb(240,240,240) srgb(240,240,240) srgb(240,240,240) srgb(240,240,240) same
"pixel:u-1.23e-4" srgb(66.654366%,73.321033%,86.654365%) srgb(66.654366%,73.321033%,86.654365%) srgb(66.654366%,73.321033%,86.654365%) srgb(66.654366%,73.321033%,86.654365%) same
"pixel:u-1.23e-4*2" srgb(66.642064%,73.308736%,86.642069%) srgb(66.642064%,73.308736%,86.642069%) srgb(66.642064%,73.308736%,86.642069%) srgb(66.642064%,73.308736%,86.642069%) same
"pixel:u-gray47" srgb(50.000001,67.000004,101) srgb(50.000001,67.000004,101) srgb(50.000001,67.000004,101) srgb(50.000001,67.000004,101) same
"pixel:u-gray47*2" srgb(-27.450982%,-20.784314%,-7.4509807%) srgb(-27.450982%,-20.784314%,-7.4509807%) srgb(-27.450982%,-20.784314%,-7.4509807%) srgb(-27.450982%,-20.784314%,-7.4509807%) same
"pixel:u" srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) same
"pixel:v" srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) same
"pixel:s" srgb(170.00001,187,221) srgb(102,85.000003,68.000004) srgb(170.00001,187,221) srgb(102,85.000003,68.000004) same
"pixel:u[0]" srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) same
"pixel:u[1-1]" srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) same
"pixel:u[1]" srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) same
"pixel:u.p[0,0]" srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) same
"pixel:v.p[0,0]" srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) same
"pixel:s.p[0,0]" srgb(170.00001,187,221) srgb(102,85.000003,68.000004) srgb(170.00001,187,221) srgb(102,85.000003,68.000004) same
"pixel:u[0].p[0,0]" srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) same
"pixel:u[1-1].p[0,0]" srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) srgb(170.00001,187,221) same
"pixel:u[1].p[0,0]" srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) same
"pixel:u.g" srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) same
"pixel:v.g" srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) same
"pixel:s.g" srgb(187,187,187) srgb(85.000003,85.000003,85.000003) srgb(187,187,187) srgb(85.000003,85.000003,85.000003) same
"pixel:u[0].g" srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) same
"pixel:u[1-1].g" srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) same
"pixel:u[1].g" srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) same
"pixel:u.p[0,0].g" srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) same
"pixel:v.p[0,0].g" srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) same
"pixel:s.p[0,0].g" srgb(187,187,187) srgb(85.000003,85.000003,85.000003) srgb(187,187,187) srgb(85.000003,85.000003,85.000003) same
"pixel:u[0].p[0,0].g" srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) same
"pixel:u[1-1].p[0,0].g" srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) srgb(187,187,187) same
"pixel:u[1].p[0,0].g" srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) same
"pixel:u.saturation" srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) same
"pixel:v.saturation" srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) same
"pixel:s.saturation" srgb(42.857143%,42.857143%,42.857143%) srgb(51.000001,51.000001,51.000001) srgb(42.857143%,42.857143%,42.857143%) srgb(51.000001,51.000001,51.000001) same
"pixel:u[0].saturation" srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) same
"pixel:u[1-1].saturation" srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) same
"pixel:u[1].saturation" srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) same
"pixel:u.p[0,0].saturation" srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) same
"pixel:v.p[0,0].saturation" srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) same
"pixel:s.p[0,0].saturation" srgb(42.857143%,42.857143%,42.857143%) srgb(51.000001,51.000001,51.000001) srgb(42.857143%,42.857143%,42.857143%) srgb(51.000001,51.000001,51.000001) same
"pixel:u[0].p[0,0].saturation" srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) same
"pixel:u[1-1].p[0,0].saturation" srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) srgb(42.857143%,42.857143%,42.857143%) same
"pixel:u[1].p[0,0].saturation" srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) srgb(51.000001,51.000001,51.000001) same
"pixel:u.median" srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) same
"pixel:v.median" srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) same
"pixel:s.median" srgb(75.555557%,75.555557%,75.555557%) srgb(85.000003,85.000003,85.000003) srgb(75.555557%,75.555557%,75.555557%) srgb(85.000003,85.000003,85.000003) same
"pixel:u[0].median" srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) same
"pixel:u[1-1].median" srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) srgb(75.555557%,75.555557%,75.555557%) same
"pixel:u[1].median" srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) srgb(85.000003,85.000003,85.000003) same

The script goodpc.bat tests examples of "%[...]" that were kindly supplied by GeeMack. (Many thanks, GeeMack!) For these tests, occurrences of "rand()" were changed to "0.23". This exposed two bugs in the new fx, now fixed, so all examples create identical outputs for the old and new fx code.

call f:\web\im\geemack\goodpc.bat
format string old result new result same/different
"%[fx:var=ceil(0.23*120+60);alt(var)*var]" 88 88 88 88 same
"%[fx:t==0?0.23*32:t==1?0.23*32+16:0.23*32+32]" 7.36 23.36 7.36 23.36 same
"%[pixel:p{0.23*w,0.23*h}]" srgb(170.00001,187,221) srgb(102,85.000003,68.000004) srgb(170.00001,187,221) srgb(102,85.000003,68.000004) same
"%[pixel:p{s.w/2,s.h/2}]" srgb(170.00001,187,221) srgb(102,85.000003,68.000004) srgb(170.00001,187,221) srgb(102,85.000003,68.000004) same
"%[pixel:u[-1].p{0.23*w,0.23*h}]" srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) same
"%[pixel:u[-1].p{t*2,0}]" srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) same
"%[pixel:u[-1].p{u[-1].w-2-(t*2),0}]" srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) srgb(102,85.000003,68.000004) same
"%[fx:(mean<0.5)*50]" 0 50 0 50 same
"%[fx:(page.width>page.height)*30]" 0 0 0 0 same
"%[fx:(t?80:60)-(mean*100)]" -15.555556 46.666667 -15.555556 46.666667 same
"%[fx:(w>h)*90]" 0 0 0 0 same
"%[fx:180/page.y]" 1.8e+14 1.8e+14 1.8e+14 1.8e+14 same
"%[fx:50-(mean*100)]" -25.555556 16.666667 -25.555556 16.666667 same
"%[fx:alt(int(0.23*100))*(0.23*30+15)]" -21.9 -21.9 -21.9 -21.9 same
"%[fx:alt(0.23*1000)*((0.23*h*0.025)+(h*0.025))]" 0.03075 0.03075 0.03075 0.03075 same
"%[fx:alt(round(0.23))*(0.23*120+120)]" 147.6 147.6 147.6 147.6 same
"%[fx:alt(t%2)*(round(0.23*5+4)*64)]" 320 -320 320 -320 same
"%[fx:alt(t)*(0.23*30+15)]" 21.9 -21.9 21.9 -21.9 same
"%[fx:alt(t)*w/2]" 0.5 -0.5 0.5 -0.5 same
"%[fx:ceil(h*tan(pi/%SLICES%))]" 1 1 1 1 same
"%[fx:ceil(h*tan(pi/page.x)*1.5)]" -0 -0 -0 -0 same
"%[fx:ceil(0.23*2)+1]" 2 2 2 2 same
"%[fx:ceil(0.23*3)]" 1 1 1 1 same
"%[fx:floor(n/2)-1]" 0 0 0 0 same
"%[fx:floor(0.23*12)+8]" 10 10 10 10 same
"%[fx:h-((t*h*0.05)+(h*0.1))]" 0.9 0.85 0.9 0.85 same
"%[fx:hypot(w,h)-h]" 0.41421356 0.41421356 0.41421356 0.41421356 same
"%[fx:int(0.23*2+2)]" 2 2 2 2 same
"%[fx:max(page.width,page.height)*1.1]" 1.1 1.1 1.1 1.1 same
"%[fx:max(u[-1].w,u[-1].h)*1.1]" 1.1 1.1 1.1 1.1 same
"%[fx:n%2?0:n]" 2 2 2 2 same
"%[fx:page.y+page.height]" 1 1 1 1 same
"%[fx:0.23*(h*0.5)+(h*0.5)]" 0.615 0.615 0.615 0.615 same
"%[fx:round(0.23)*180/page.x]" 0 0 0 0 same
"%[fx:t*((u[-1].h-u[0].h)/n)+u[0].h]" 1 1 1 1 same
"%[fx:t==0?0.23*32:t==1?0.23*32+16:0.23*32+32]" 7.36 23.36 7.36 23.36 same
"%[fx:var=ceil(0.23*120+60);alt(var)*var]" 88 88 88 88 same

Error checking and reporting

Here are some invalid input strings, with each resulting error message. This error checking is done at translation, and has no impact on run-time performance.

-fx input string Error message
23 /*+- Expected operand at '*+-' @ error/fx.c/TranslateExpression/2595.
23>> Expected operand after operator at '' @ error/fx.c/TranslateExpression/2579.
23 / Expected operand after operator at '' @ error/fx.c/TranslateExpression/2579.
10--2 Attempted update to non-UserSymbol '' at '2' @ error/fx.c/TranslateExpression/2537.
3-1 ? 4+5 ? 6 : 7 :2*3 Already have '?' in sub-expression at '6 : 7 :2*3' @ error/fx.c/ProcessTernaryOpr/2318.
? Expected operand at '?' @ error/fx.c/GetOperand/2298.
: Expected operand at ':' @ error/fx.c/GetOperand/2298.
3-1 ? : 4+5 Expected operand at ': 4+5' @ error/fx.c/TranslateExpression/2595.
aa=1 ? 34:45:56 Need '?' in sub-expression at '56' @ error/fx.c/ProcessTernaryOpr/2338.
aa=1 ? 34:45?56 '?' with no corresponding ':' '' at '' @ error/fx.c/ResolveTernaryAddresses/2458.
abs = 2+3 Expected char '(' at '= 2+3' @ error/fx.c/ExpectChar/1267.
r = 2+3 Attempted assignment to non-UserSymbol 'r' at '2+3' @ error/fx.c/TranslateExpression/2530.
epsilon = 2+3 Attempted assignment to non-UserSymbol 'epsilon' at '2+3' @ error/fx.c/TranslateExpression/2530.
s[0,1,2,3,4,5,6,7,8,9] Not a real operator at '[0,1,2,3,4,5,6,7,8,9...' @ error/fx.c/GetOperator/2377.
max(5,11,3,6) For function 'max', arguments don't end with ')' at '3,6)' @ error/fx.c/GetFunction/1870.
abs Expected char '(' at '' @ error/fx.c/ExpectChar/1267.
page.bad Attribute 'page' needs qualifier at '' @ error/fx.c/GetImgAttrToken/1448.
resolution.width Attribute 'resolution' needs qualifier at '' @ error/fx.c/GetImgAttrToken/1448.
u.bad For function 'u', bad qualifier 'bad' at 'bad' @ error/fx.c/GetFunction/1933.
page Attribute 'page' needs qualifier at '' @ error/fx.c/GetImgAttrToken/1448.
() Empty expression in parentheses at '' @ error/fx.c/GetOperand/2033.
(xx=123 '(' but no ')' at '' @ error/fx.c/GetOperand/2040.
abs () For function 'abs' expected 1 arguments, found too few (0) at '' @ error/fx.c/GetFunction/1857.
(3+ Empty expression in parentheses at '' @ error/fx.c/GetOperand/2033.
abs(12,) For function 'abs', arguments don't end with ')' at ')' @ error/fx.c/GetFunction/1870.
abs(12,34,56) For function 'abs', arguments don't end with ')' at '34,56)' @ error/fx.c/GetFunction/1870.
max(5,11,3,6) For function 'max', arguments don't end with ')' at '3,6)' @ error/fx.c/GetFunction/1870.
for (,,) For function 'for' expected 3 arguments, found too few (0) at '' @ error/fx.c/GetFunction/1857.
for (1,2) For function 'for' expected 3 arguments, found too few (2) at '' @ error/fx.c/GetFunction/1857.
mean.bad Bad channel qualifier at 'bad' @ error/fx.c/GetOperand/2213.
v Symbol 'v' but fewer than two images at 'v' @ error/fx.c/GetOperand/2179.
3 4 Expected operator at '4' @ error/fx.c/GetOperator/2385.
3 + * Expected operand at '*' @ error/fx.c/TranslateExpression/2595.
3 * Expected operand after operator at '' @ error/fx.c/TranslateExpression/2579.
3 ] Not a real operator at ']' @ error/fx.c/GetOperator/2377.
3 + 4 ) Not a real operator at ')' @ error/fx.c/GetOperator/2377.
3 ? 4 ? 5 : 6 Already have '?' in sub-expression at '5 : 6' @ error/fx.c/ProcessTernaryOpr/2318.
3 ? 4 : 5 : 6 Need '?' in sub-expression at '6' @ error/fx.c/ProcessTernaryOpr/2338.
3 : 4 Need '?' in sub-expression at '4' @ error/fx.c/ProcessTernaryOpr/2338.
xx = 3 + yy NewUserSymbol 'yy' after non-assignment operator at '' @ error/fx.c/TranslateExpression/2603.
xx NewUserSymbol 'xx' needs assignment operator at '' @ error/fx.c/TranslateExpression/2619.
xx++ Expected assignment after new UserSymbol 'xx' at '' @ error/fx.c/TranslateExpression/2523.
#badhex Bad hex number at '#badhex' @ error/fx.c/GetOperand/2091.
#a Bad hex number at '#a' @ error/fx.c/GetOperand/2091.
#z Bad hex number at '#z' @ error/fx.c/GetOperand/2091.
#abcde Bad hex number at '#abcde' @ error/fx.c/GetOperand/2091.
xx+=2 Expected assignment after new UserSymbol 'xx' at '2' @ error/fx.c/TranslateExpression/2523.
2=3 Attempted assignment to non-UserSymbol '' at '3' @ error/fx.c/TranslateExpression/2530.
r=2 Attempted assignment to non-UserSymbol 'r' at '2' @ error/fx.c/TranslateExpression/2530.
abs=2 Expected char '(' at '=2' @ error/fx.c/ExpectChar/1267.
2+=3 Attempted update to non-UserSymbol '' at '3' @ error/fx.c/TranslateExpression/2537.
r+=2 Attempted update to non-UserSymbol 'r' at '2' @ error/fx.c/TranslateExpression/2537.
abs+=2 Expected char '(' at '+=2' @ error/fx.c/ExpectChar/1267.
xx=2; xx++ *3 '++' and '--' must be the final operators in an expression at '*3' @ error/fx.c/TranslateExpression/2587.
2+xx+3 NewUserSymbol 'xx' after non-assignment operator at '+3' @ error/fx.c/TranslateExpression/2603.
u[-1].p[3,4].mean For function 'p', bad qualifier 'mean' at 'mean' @ error/fx.c/GetFunction/1933.
12*(34-5)) Not a real operator at ')' @ error/fx.c/GetOperator/2377.
-xx After unary, NewUserSymbol at '' @ error/fx.c/GetOperand/2070.
--xx After unary, bad operand at '' @ error/fx.c/GetOperand/2062.
u.p[0,0].median For function 'p', bad qualifier 'median' at 'median' @ error/fx.c/GetFunction/1933.
v.p[0,0].median Symbol 'v' but fewer than two images at 'v.p[0,0].median' @ error/fx.c/GetOperand/2179.
s.p[0,0].median For function 'p', bad qualifier 'median' at 'median' @ error/fx.c/GetFunction/1933.
u[0].p[0,0].median For function 'p', bad qualifier 'median' at 'median' @ error/fx.c/GetFunction/1933.
u[1-1].p[0,0].median For function 'p', bad qualifier 'median' at 'median' @ error/fx.c/GetFunction/1933.
u[1].p[0,0].median For function 'p', bad qualifier 'median' at 'median' @ error/fx.c/GetFunction/1933.
HCL(113 constant color missing ')' at 'HCL(113' @ error/fx.c/GetConstantColour/1597.

A message that includes "ValStack underflow" suggests the translator has a bug. The count of "underflow" messages in the above is: 0 .

A small selection of Fred's ImageMagick scripts were executed in sequence for the old "-fx" and the new "-fx2". For convenience on my computer, they were first modified to use the "magick" command. The elapsed times were measured, and the outputs from the old and new "-fx" were compared with "-metric RMSE".

The scripts were: adaptivegamma, defisheye, disperse, pano2rect, sharpedge, statsfilt, tunnelize, warplog and xpand.

The "disperse" script uses randomness, creating a different result each time, so the RMSE difference from that script was ignored.

The table shows the worst RMSE of the scripts (excluding "disperse"), on a nominal scale of 0.0 to 1.0. An RMSE of less than 1e-02 will generally not be noticable.

Input file Size (pixels) Old "-fx" New "-fx2" Worst RMSE
toes.png 267x233 3096 seconds 124 seconds 1.13239e-05

Many small images

The new fx code was developed to increase performance of large images, by decreasing the processing required at each pixel, at the expense of increasing the processing required at each image, which includes more extensive syntax checking and translation to a run-time RPN language.

A consequence is that the total processing required for small images has increased. We want to ensure the reduced performance is not excessive.

%FXOLD%magick xc:white -duplicate 999 +noise random -brightness-contrast %[fx:50-(mean*100)] null:
%FXNEW%magick xc:white -duplicate 999 +noise random -brightness-contrast %[fx:50-(mean*100)] null:
0 00:00:10
0 00:00:11

The times are shown in the format "D HH:MM:SS".

%FXOLD%magick xc:white -duplicate 999 +noise random -fx (50-(mean*100))/100 null:
%FXNEW%magick xc:white -duplicate 999 +noise random -fx (50-(mean*100))/100 null:
0 00:00:11
0 00:00:26

Conclusion: the new fx code does decrease performance when we have many small image, but this is not excessive.

Scripts

For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.

The scripts use some utility programs such as StopWatchcGrep and chStrs. I do not supply the source or binaries of these.

testPerf.bat

set IMG=%~1
if "%IMG%"=="" set IMG=-size 1000x1000 xc:#abd

set SCRFILE=tp.scr

echo off

(
  for /F "tokens=*" %%L in (%~dp0testPerf.txt) do (
    echo ^( -clone 0 -fx "%%L" +delete ^)
  )

  echo NULL:
) >%SCRFILE%

echo on

type %SCRFILE%


call StopWatch
%FXOLD%magick %IMG% -script %SCRFILE%
call StopWatch
%FXNEW%magick %IMG% -script %SCRFILE%
call StopWatch

goodFxSyntax.bat

set xc2=xc:#abd xc:#432

%FXOLD%magick %xc2% -append +repage gfs.png

set VPIX=-virtual-pixel Black
set OUTSPEC=-define quantum:format=floating-point -depth 32


echo off
(
for /F "tokens=*" %%L in (%~dp0goodfxsyntax.txt) do (
  ( %FXNEW%magick gfs.png %VPIX% -fx "%%L" %OUTSPEC% gfs_new.miff 2^>^&1 ) |tail -5

  %FXOLD%magick gfs.png %VPIX% -fx "%%L" %OUTSPEC% gfs_old.miff

  set cleaned=%%L
  set "cleaned=!cleaned:<=&lt;!"
  set "cleaned=!cleaned:>=&gt;!"
  set "cleaned=!cleaned:&=++amp++!"
  set "cleaned=!cleaned:%%=__!"
  set "cleaned=!cleaned:++amp++=&!"

  %IMG7%magick gfs_old.miff gfs_new.miff -metric RMSE -format "=start= '!cleaned!' distortion=%%[distortion] =end=\n" -compare info: 
)
) >fxn_gfs.lis 

echo on

cgrep /ifxn_gfs.lis /ofxn_gfs1a.lis /sdistortion= /f\s\r\n

chStrs /ifxn_gfs1a.lis /ofxn_gfs1a.lis /f"\(" /t^&lt;
chStrs /ifxn_gfs1a.lis /ofxn_gfs1a.lis /f"\)" /t^&gt;
chStrs /ifxn_gfs1a.lis /ofxn_gfs1a.lis /f"__" /t%%

chStrs /ifxn_gfs1a.lis /ofxn_gfs1b.lis /f"=start=" /t\(tr\)\(td\)
chStrs /ifxn_gfs1b.lis /ofxn_gfs1b.lis /f"distortion=" /t\(/td\)\(td\)
chStrs /ifxn_gfs1b.lis /ofxn_gfs1b.lis /f"=end=" /t\(/td\)\(/tr\)

cPrefix /ifxn_gfs1b.lis /X /t"\(tr\)\(th\)-fx input string\(/th\)\(th\)distortion\(/th\)\(/tr\)"
cPrefix /ifxn_gfs1b.lis /X /t"\(table\)" /b"\(/table\)"


echo off
(
for /F "tokens=*" %%L in (%~dp0goodfxsyntax2.txt) do (
  ( %FXNEW%magick -size 4x4 %xc2% %VPIX% -fx "%%L" %OUTSPEC% gfs2_new.miff 2^>^&1 ) |tail -5

  %FXOLD%magick -size 4x4 %xc2% %VPIX% -fx "%%L" %OUTSPEC% gfs2_old.miff

  set cleaned=%%L

  set cleaned=!cleaned:%%=__!

  %IMG7%magick gfs2_old.miff gfs2_new.miff -metric RMSE -format "=start= '!cleaned!' distortion=%%[distortion] =end=\n" -compare info:
)
) >fxn_gfs2.lis

echo on

cgrep /ifxn_gfs2.lis /ofxn_gfs2a.lis /sdistortion= /f\s\r\n

chStrs /ifxn_gfs2a.lis /ofxn_gfs2b.lis /f"=start=" /t\(tr\)\(td\)
chStrs /ifxn_gfs2b.lis /ofxn_gfs2b.lis /f"distortion=" /t\(/td\)\(td\)
chStrs /ifxn_gfs2b.lis /ofxn_gfs2b.lis /f"=end=" /t\(/td\)\(/tr\)

cPrefix /ifxn_gfs2b.lis /X /t"\(tr\)\(th\)-fx input string\(/th\)\(th\)distortion\(/th\)\(/tr\)"
cPrefix /ifxn_gfs2b.lis /X /t"\(table\)" /b"\(/table\)"


echo off
(
for /F "tokens=*" %%L in (%~dp0goodBadFxSyntax.txt) do (
  ( %FXNEW%magick -size 4x4 %xc2% %VPIX% -fx "%%L" %OUTSPEC% gfs3_new.miff 2^>^&1 ) |tail -5

  %FXOLD%magick -size 4x4 %xc2% %VPIX% -fx "%%L" %OUTSPEC% gfs3_old.miff

  set cleaned=%%L

  set cleaned=!cleaned:%%=__!

  %IMG7%magick gfs3_old.miff gfs3_new.miff -metric RMSE -format "=start= '!cleaned!' distortion=%%[distortion] =end=\n" -compare info:
)
) >fxn_gfs3.lis

echo on

cgrep /ifxn_gfs3.lis /ofxn_gfs3a.lis /sdistortion= /f\s\r\n

chStrs /ifxn_gfs3a.lis /ofxn_gfs3b.lis /f"=start=" /t\(tr\)\(td\)
chStrs /ifxn_gfs3b.lis /ofxn_gfs3b.lis /f"distortion=" /t\(/td\)\(td\)
chStrs /ifxn_gfs3b.lis /ofxn_gfs3b.lis /f"=end=" /t\(/td\)\(/tr\)

cPrefix /ifxn_gfs3b.lis /X /t"\(tr\)\(th\)-fx input string\(/th\)\(th\)distortion\(/th\)\(/tr\)"
cPrefix /ifxn_gfs3b.lis /X /t"\(table\)" /b"\(/table\)"

goodpc.bat

set IMGS=xc:#abd xc:#654

set SLICES=5

chStrs /i%~dp0goodpc.txt /ogoodpc_norand.txt /frand() /t0.23

%FXNEW%magick %IMGS% -define fx:debug=true -format "%%[fx:%~1]\n" info:

echo off
(
  for /F "tokens=*" %%L in (goodpc_norand.txt) do (
    for /F "usebackq tokens=*" %%B in (`%FXOLD%magick %IMGS% -format "<td>%%L</td>" info:`) do set SOLD=%%B

    for /F "usebackq tokens=*" %%B in (`%FXNEW%magick %IMGS% -format "<td>%%L</td>" info:`) do set SNEW=%%B

    set goodBad=same

    if !SOLD! NEQ !SNEW! set goodBad=DIFFERENT

    set NoLtGt=%%L
    set "NoLtGt=!NoLtGt:<=&lt;!"
    set "NoLtGt=!NoLtGt:>=&gt;!"

    echo =start= "!NoLtGt!" =mid= !SOLD! !SNEW! =mid2= !goodBad! =end=
  )
) >fxn_ft.lis

cGrep /ifxn_ft.lis /ofxn_ftb.lis /srand() /x

chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=start=" /t"\(tr\)\(td\)"
chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=mid=" /t"\(/td\)"
chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=mid2=" /t"\(td\)"
chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=end=" /t"\(/td\)\(/tr\)"

cPrefix /ifxn_ftb.lis /X /t"\(tr\)\(th\)format string\(/th\)\(th cspan\)old result\(/th\)\(th cspan\)new result\(/th\)\(th\)same/different\(/th\)\(/tr\)"
cPrefix /ifxn_ftb.lis /X /t"\(table\)" /b"\(/table\)"

chStrs /ifxn_ftb.lis /ofxn_ft_gm.lis /fcspan /tcolspan=\q2\q

echo on

badFxSyntax.bat

set LIS_FILE=%1

if "%LIS_FILE%"=="" set LIS_FILE=fxn_err.lis

echo off

(
echo ^<table^>
echo ^<tr^>^<th^>-fx input string^</th^>^<th^>Error message^</th^>^</tr^>

for /F "tokens=*" %%A in (%~dp0badfxsyntax.txt) do (
  for /F "usebackq tokens=*" %%B in (`%FXNEW%magick xc:#8bd -fx "%%A" NULL: 2^>^&1`) do set msg=%%B

  set msg2=!msg:magick: =!

  if !msg2! NEQ !msg! (
    set msg3=!msg2:fatal/fx2.inc/=!
    echo ^<tr^>^<td^>%%A^</td^>^<td^>!msg3!^</td^>^</tr^>
  )
)
echo ^</table^>
) >%LIS_FILE%

echo on

echo created %LIS_FILE%

fmtTst.bat

set IMGS=xc:#abd xc:#654

%FXNEW%magick %IMGS% -define fx:debug=true -format "%%[fx:%~1]\n" info:

%FXOLD%magick %IMGS% -format "%%[fx:%~1]\n" info:


for %%A in (fx) do (

  echo %%A

  echo off
  (
    for /F "tokens=*" %%L in (%~dp0fmtTstDiff.txt) do (
      for /F "usebackq tokens=*" %%B in (`%FXOLD%magick %IMGS% -format "<td>%%[%%A:%%L]</td>" info:`) do set SOLD=%%B

      for /F "usebackq tokens=*" %%B in (`%FXNEW%magick %IMGS% -format "<td>%%[%%A:%%L]</td>" info:`) do set SNEW=%%B

      set goodBad=same

      if !SOLD! NEQ !SNEW! set goodBad=DIFFERENT

      echo =start= "%%A:%%L" =mid= !SOLD! !SNEW! =mid2= !goodBad! =end=
    )
  ) >fxn_ft.lis
  echo on

  chStrs /ifxn_ft.lis /ofxn_ftb.lis /f"=start=" /t"\(tr\)\(td\)"
  chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=mid=" /t"\(/td\)"
  chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=mid2=" /t"\(td\)"
  chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=end=" /t"\(/td\)\(/tr\)"

  cPrefix /ifxn_ftb.lis /X /t"\(tr\)\(th\)format string\(/th\)\(th cspan\)old result\(/th\)\(th cspan\)new result\(/th\)\(th\)same/different\(/th\)\(/tr\)"
  cPrefix /ifxn_ftb.lis /X /t"\(table\)" /b"\(/table\)"

  chStrs /ifxn_ftb.lis /ofxn_ft_diff_%%A.lis /fcspan /tcolspan=\q2\q
)

for %%A in (fx pixel hex) do (

  echo %%A

  echo off
  (
    for /F "tokens=*" %%L in (%~dp0fmtTst.txt) do (
      for /F "usebackq tokens=*" %%B in (`%FXOLD%magick %IMGS% -format "<td>%%[%%A:%%L]</td>" info:`) do set SOLD=%%B

      for /F "usebackq tokens=*" %%B in (`%FXNEW%magick %IMGS% -format "<td>%%[%%A:%%L]</td>" info:`) do set SNEW=%%B

      set goodBad=same

      if !SOLD! NEQ !SNEW! set goodBad=DIFFERENT

      echo =start= "%%A:%%L" =mid= !SOLD! !SNEW! =mid2= !goodBad! =end=
    )
  ) >fxn_ft.lis
  echo on

  chStrs /ifxn_ft.lis /ofxn_ftb.lis /f"=start=" /t"\(tr\)\(td\)"
  chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=mid=" /t"\(/td\)"
  chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=mid2=" /t"\(td\)"
  chStrs /ifxn_ftb.lis /ofxn_ftb.lis /f"=end=" /t"\(/td\)\(/tr\)"

  cPrefix /ifxn_ftb.lis /X /t"\(tr\)\(th\)format string\(/th\)\(th cspan\)old result\(/th\)\(th cspan\)new result\(/th\)\(th\)same/different\(/th\)\(/tr\)"
  cPrefix /ifxn_ftb.lis /X /t"\(table\)" /b"\(/table\)"

  chStrs /ifxn_ftb.lis /ofxn_ft_%%A.lis /fcspan /tcolspan=\q2\q
)

All images on this page were created by the commands shown, using:

%FXOLD%magick identify -version
Version: ImageMagick 7.1.0-20 Q32-HDRI x86_64 2021-12-29 https://imagemagick.org
Copyright: (C) 1999-2021 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(4.5) 
Delegates (built-in): bzlib cairo fontconfig fpx freetype jbig jng jpeg lcms ltdl lzma pangocairo png raqm rsvg tiff webp wmf x xml zip zlib
Compiler: gcc (11.2)
%FXNEW%magick identify -version
Version: ImageMagick 7.1.0-20 Q32-HDRI x86_64 2022-01-16 https://imagemagick.org
Copyright: (C) 1999-2021 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(4.5) 
Delegates (built-in): bzlib cairo fontconfig fpx freetype jbig jng jpeg lcms ltdl lzma pangocairo png raqm rsvg tiff webp wmf x xml zip zlib
Compiler: gcc (11.2)

To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG or TIFF or MIFF to JPG.

Source file for this web page is fxntest.h1. To re-create this web page, execute "procH1 fxntest".


This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.

Anyone is permitted to re-publish this page, but only for non-commercial use.

Anyone is permitted to link to this page, including for commercial use.


Page version v1.0 8-January-2022.

Page created 24-Jan-2022 18:19:39.

Copyright © 2022 Alan Gibson.