Reminds me of J. Tarbell’s and Mike Kershaw’s Substrate.
Two dire warnings of the link not being HTTPS. Curiosity triumphs.
It does look like that. The ideal way of making it involves boolean operation, but I don’t think G’MIC language supports boolean operation for polygon and eclipse. The other way of doing is via recursive generative with as many images and maybe string to JIT code approach which is really not ideal to have to do and having to do that to try to multithread Diffusion Limited Aggregation, it is hard. But, maybe my rectangular division filter would help, I think that would. Lots of approach coming to think of it, but none very ideal.
Yes, I’m reading that transformative popcorn fractal document again. Basically, this is a fork of the Transformative Popcorn Fractal, and I call this variation Swirling Hall. Maybe I’ll combine them, but I don’t feel like combining them as that’ll take time.
EDIT:
I wasn’t able to make the last picture found in that document, but after refactoring and adding a option to use - symbol to define if it a negative variable, I was able to do this. The prepend operator (..=) is useful. I thought I never needed that.

Also, I’m looking into combining Swirling Hall and Popcorn Fractal [Transformative]. Nailed it.
What happens if you use recursions instead of periodic functions ?
It is already based on recursion.
Just showing off the animation version of the combined Transformative Popcorn Fractal/Swirling Hall filter.
I had optimized Tiled Form or rep_form_pixel. There is a pretty weird bug where CMYK is faster than other non-rgb space, and I do not know why yet. Other than that, it is 3-7 times faster than the old version. It is faster because I used some clever way of stimulating the old version through the use of multiple arrays and array_resize.
Ok, what if you then use periodic functions instead of recursions? ![]()
Ok, looks like I"m having a little trouble here. How come this doesn’t have a working dynamic gui interface?
#@gui Color Harmonies: fx_rep_color_harmonies
#@gui :_=separator(),_=note("<b>Reference Point</b>")
#@gui :1.Hue=float(50,0,360)
#@gui :2.Saturation(%)=float(100,0,100)
#@gui :3.Shade/Tint(%)=float(0,-100,100)
#@gui :4.Color Space=choice(0,"RGB",RYB")
#@gui :_=separator(),_=note("<b>Additional Information</b>")
#@gui :5.Palette Mode=choice(0,"Neutral 8","Neutral 15","Analogous 30","Complementary","Split-Complementary","Triadic","Tetradic","Clash","Four Tones","Five Tones","Six Tones")
#@gui :_=separator(),_=note("<b>Output Color</b>")
#@gui :6.7.8.Color A=color(0,0,0)
#@gui :9.10.11.Color B=color(0,0,0)
#@gui :12.13.14.Color C=color(0,0,0)
#@gui :15.16.17.Color D=color(0,0,0)
#@gui :18.19.20.Color E=color(0,0,0)
#@gui :21.22.23.Color F=color(0,0,0)
#@gui :_=separator(),_=note("<b>Preview</b>")
#@gui :24.25.Point Position=point(50,50,0,1,128,128,128,255)
#@gui :26.Scaling(%)=float(90,30,100)
#@gui :27.28.Point=point(50,50,0,1,128,128,128,255)_0
#@gui :29.30.31.Color A=color(0,0,0)
#@gui :32.33.34.Color B=color(0,0,0)
#@gui :35.36.37.Color C=color(0,0,0)
#@gui :38.39.40.Color D=color(0,0,0)
#@gui :41.42.43.Color E=color(0,0,0)
#@gui :44.45.46.Color F=color(0,0,0)
#@gui :47a.Hue=float(0,0,360)
#@gui :48a.Saturation(%)=float(100,0,100)
#@gui :49a.Shade/Tint(%)=float(0,-100,100)
#@gui :50b.Hue=float(0,0,360)
#@gui :51b.Saturation(%)=float(100,0,100)
#@gui :52b.Shade/Tint(%)=float(0,-100,100)
#@gui :53c.Hue=float(0,0,360)
#@gui :54c.Saturation(%)=float(100,0,100)
#@gui :55c.Shade/Tint(%)=float(0,-100,100)
#@gui :56d.Hue=float(0,0,360)
#@gui :57d.Saturation(%)=float(100,0,100)
#@gui :58d.Shade/Tint(%)=float(0,-100,100)
#@gui :59e.Hue=float(0,0,360)
#@gui :60e.Saturation(%)=float(100,0,100)
#@gui :61e.Shade/Tint(%)=float(0,-100,100)
#@gui :62f.Hue=float(0,0,360)
#@gui :63f.Saturation(%)=float(100,0,100)
#@gui :64f.Shade/Tint(%)=float(0,-100,100)
#@gui :65.Point-X=float(50,-100,200)
#@gui :66.Point-Y=float(50,-100,200)
#@gui :67.Preview Palette?=bool(0)
#@gui :68.Orientation=choice(0,"Horizontal","Vertical")
#@gui :69.Palette X=choice(1,"Bottom","Middle","Top")
#@gui :70.Palette Y=choice(1,"Left","Middle","Top")
fx_rep_color_harmonies:
# snipped code
u "{$hsl_h}"\
"{$hsl_s}"\
"{$hsl_l}"\
"{$4}"\
"{$5}"\
"{$rgb_0_r,$rgb_0_g,$rgb_0_b}"\
"{$rgb_1_r,$rgb_1_g,$rgb_1_b}"\
"{$rgb_2_r,$rgb_2_g,$rgb_2_b}"\
"{$rgb_3_r,$rgb_3_g,$rgb_3_b}"\
"{$rgb_4_r,$rgb_4_g,$rgb_4_b}"\
"{$rgb_5_r,$rgb_5_g,$rgb_5_b}"\
"{$24,$25}"\
"{$26}"\
"{$27,$28}"\
"{$rgb_0_r_alt,$rgb_0_g_alt,$rgb_0_b_alt}"\
"{$rgb_1_r_alt,$rgb_1_g_alt,$rgb_1_b_alt}"\
"{$rgb_2_r_alt,$rgb_2_g_alt,$rgb_2_b_alt}"\
"{$rgb_3_r_alt,$rgb_3_g_alt,$rgb_3_b_alt}"\
"{$rgb_4_r_alt,$rgb_4_g_alt,$rgb_4_b_alt}"\
"{$rgb_5_r_alt,$rgb_5_g_alt,$rgb_5_b_alt}"\
"{$hsl_0_h}"\
"{$hsl_0_s}"\
"{$hsl_0_l}"\
"{$hsl_1_h}"\
"{$hsl_1_s}"\
"{$hsl_1_l}"\
"{$hsl_2_h}"\
"{$hsl_2_s}"\
"{$hsl_2_l}"\
"{$hsl_3_h}"\
"{$hsl_3_s}"\
"{$hsl_3_l}"\
"{$hsl_4_h}"\
"{$hsl_4_s}"\
"{$hsl_4_l}"\
"{$hsl_5_h}"\
"{$hsl_5_s}"\
"{$hsl_5_l}"\
"{$65}"\
"{$66}"\
"{$67}"\
"{$68}"\
"{$69}"\
"{$70}"
Full Code
#@cli rep_hsl2ryb2rgb
#@cli : Convert color representation of selected image from HSL to RYB to RGB
rep_hsl2ryb2rgb:
e[^-1] "Convert color representation of image$? from HSL to RYB to RGB."
f "H=(i0/60)%6;C=(1-abs(2*i2-1))*i1;X=C*(1-abs(H%2-1));
m=i2-C/2;
RYB=arg(1+int(H),[C,X,0],[X,C,0],[0,C,X],[0,X,C],[X,0,C],[C,0,X]);
RYB+=m*=255;
red=RYB[0];
yellow=RYB[1];
blue=RYB[2];
white=min(RYB);
red-=white;
yellow-=white;
blue-=white;
maxyellow=max(red,yellow,blue);
green=min(yellow,blue);
yellow-=green;
blue-=green;
blue>0&&green>0?(
blue*=2;
green*=2
);
red+=yellow;
green+=yellow;
maxgreen = max(red,green,blue);
maxgreen>0?(
N=maxyellow/maxgreen;
red*=N;
green*=N;
blue*=N;
);
red+=white;
green+=white;
blue+=white;
[red,green,blue];"
#@cli rep_color_harmony_palette: -360<=ang<=360,0<=_saturation<=1,-100[%]<=shade_tint<=100[%],0<=choice<=10,ryb_mode={ 0=rgb | 1=ryb }
#@cli : Create a harmony palette. In other word, create a palette based on the color wheel.
+rep_color_harmony_palette:
ang,saturation,shade_tint,choice,ryb_mode=${1-5}
{arg(1+$choice%11,6,6,6,2,3,3,4,3,4,5,6)},1,1,3,">begin(
fmod(a)=a-360*floor(a/360);
const start_ang=fmod($ang);
const saturation=cut($saturation,0,1);
const shade_tint=cut((1+$shade_tint)/2,0,1);
const choice=$choice%11;
ang=start_ang;
choice<3?( #Neutral 8-15 and Analogous 30
const add_ang=arg(choice+1,8,15,30);
new_ang()=x?(ang+=add_ang;ang=fmod(ang););
):
choice==3?( #Complementary
new_ang()=x?ang=fmod(ang+180);
):
choice==4?( #Split-Complementary
new_ang()=x==2?(ang+=60;ang=fmod(ang);):x==1?(ang+=150;ang=fmod(ang););
):
choice==5?( #Triadic
new_ang()=x?ang=fmod(ang+120);
):
choice==6?( #Tetradic
new_ang()=x?ang=fmod(ang+90);
):
choice==7?( #Clash
new_ang()=x?(ang=fmod(start_ang+(x%2?90:-90)));
):
choice==8?( #Four Tones
new_ang()=x?(ang=fmod(ang+arg(x%2+1,120,60)););
):
choice==9?( #Five Tones
new_ang()=x?(x==1?(ang=fmod(ang+120);):(ang=fmod(ang+arg(x%2+1,30,60))););
):( #Six Tones
new_ang()=x?(ang=fmod(ang+(x%2?30:90)););
);
);
new_ang();
[ang,saturation,shade_tint];"
if $ryb_mode +rep_hsl2ryb2rgb. else +hsl2rgb. fi
round.
#@gui Color Harmonies: fx_rep_color_harmonies
#@gui :_=separator(),_=note("<b>Reference Point</b>")
#@gui :1.Hue=float(50,0,360)
#@gui :2.Saturation(%)=float(100,0,100)
#@gui :3.Shade/Tint(%)=float(0,-100,100)
#@gui :4.Color Space=choice(0,"RGB",RYB")
#@gui :_=separator(),_=note("<b>Additional Information</b>")
#@gui :5.Palette Mode=choice(0,"Neutral 8","Neutral 15","Analogous 30","Complementary","Split-Complementary","Triadic","Tetradic","Clash","Four Tones","Five Tones","Six Tones")
#@gui :_=separator(),_=note("<b>Output Color</b>")
#@gui :6.7.8.Color A=color(0,0,0)
#@gui :9.10.11.Color B=color(0,0,0)
#@gui :12.13.14.Color C=color(0,0,0)
#@gui :15.16.17.Color D=color(0,0,0)
#@gui :18.19.20.Color E=color(0,0,0)
#@gui :21.22.23.Color F=color(0,0,0)
#@gui :_=separator(),_=note("<b>Preview</b>")
#@gui :24.25.Point Position=point(50,50,0,1,128,128,128,255)
#@gui :26.Scaling(%)=float(90,30,100)
#@gui :27.28.Point=point(50,50,0,1,128,128,128,255)_0
#@gui :29.30.31.Color A=color(0,0,0)
#@gui :32.33.34.Color B=color(0,0,0)
#@gui :35.36.37.Color C=color(0,0,0)
#@gui :38.39.40.Color D=color(0,0,0)
#@gui :41.42.43.Color E=color(0,0,0)
#@gui :44.45.46.Color F=color(0,0,0)
#@gui :47a.Hue=float(0,0,360)
#@gui :48a.Saturation(%)=float(100,0,100)
#@gui :49a.Shade/Tint(%)=float(0,-100,100)
#@gui :50b.Hue=float(0,0,360)
#@gui :51b.Saturation(%)=float(100,0,100)
#@gui :52b.Shade/Tint(%)=float(0,-100,100)
#@gui :53c.Hue=float(0,0,360)
#@gui :54c.Saturation(%)=float(100,0,100)
#@gui :55c.Shade/Tint(%)=float(0,-100,100)
#@gui :56d.Hue=float(0,0,360)
#@gui :57d.Saturation(%)=float(100,0,100)
#@gui :58d.Shade/Tint(%)=float(0,-100,100)
#@gui :59e.Hue=float(0,0,360)
#@gui :60e.Saturation(%)=float(100,0,100)
#@gui :61e.Shade/Tint(%)=float(0,-100,100)
#@gui :62f.Hue=float(0,0,360)
#@gui :63f.Saturation(%)=float(100,0,100)
#@gui :64f.Shade/Tint(%)=float(0,-100,100)
#@gui :65.Point-X=float(50,-100,200)
#@gui :66.Point-Y=float(50,-100,200)
#@gui :67.Preview Palette?=bool(0)
#@gui :68.Orientation=choice(0,"Horizontal","Vertical")
#@gui :69.Palette X=choice(1,"Bottom","Middle","Top")
#@gui :70.Palette Y=choice(1,"Left","Middle","Top")
fx_rep_color_harmonies:
hsl_h,hsl_s,hsl_l,\
rgb_0_r,rgb_0_g,rgb_0_b,\
rgb_1_r,rgb_1_g,rgb_1_b,\
rgb_2_r,rgb_2_g,rgb_2_b,\
rgb_3_r,rgb_3_g,rgb_3_b,\
rgb_4_r,rgb_4_g,rgb_4_b,\
rgb_5_r,rgb_5_g,rgb_5_b,\
rgb_0_r_alt,rgb_0_g_alt,rgb_0_b_alt,\
rgb_1_r_alt,rgb_1_g_alt,rgb_1_b_alt,\
rgb_2_r_alt,rgb_2_g_alt,rgb_2_b_alt,\
rgb_3_r_alt,rgb_3_g_alt,rgb_3_b_alt,\
rgb_4_r_alt,rgb_4_g_alt,rgb_4_b_alt,\
rgb_5_r_alt,rgb_5_g_alt,rgb_5_b_alt,\
hsl_0_h,hsl_0_s,hsl_0_l,\
hsl_1_h,hsl_1_s,hsl_1_l,\
hsl_2_h,hsl_2_s,hsl_2_l,\
hsl_3_h,hsl_3_s,hsl_3_l,\
hsl_4_h,hsl_4_s,hsl_4_l,\
hsl_5_h,hsl_5_s,hsl_5_l\
=${1-3},${6-23},${29-64}
rep_create_hsl_color_select $2%,$24%,$4,$25%
if [${1-3}]!=[${46-48}]
+rep_color_harmony_palette $1,{$2/100},$3%,$5,$4
sh.. 1 *. 200 -. 100 sh... 2 *. 100 rm[-2,-1]
if w==2
hsl_0_h,hsl_1_h,\
hsl_0_s,hsl_1_s,\
hsl_0_l,hsl_1_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,\
rgb_0_g,rgb_1_g,\
rgb_0_b,rgb_1_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,\
rgb_0_b_alt,rgb_1_b_alt\
={crop(#-1)}
elif w==3
hsl_0_h,hsl_1_h,hsl_2_h,\
hsl_0_s,hsl_1_s,hsl_2_s,\
hsl_0_l,hsl_1_l,hsl_2_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,rgb_2_r,\
rgb_0_g,rgb_1_g,rgb_2_g,\
rgb_0_b,rgb_1_b,rgb_2_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,rgb_2_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,rgb_2_g_alt,\
rgb_0_b_alt,rgb_1_b_alt,rgb_2_b_alt\
={crop(#-1)}
elif w==4
hsl_0_h,hsl_1_h,hsl_2_h,hsl_3_h,\
hsl_0_s,hsl_1_s,hsl_2_s,hsl_3_s,\
hsl_0_l,hsl_1_l,hsl_2_l,hsl_3_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,rgb_2_r,rgb_3_r,\
rgb_0_g,rgb_1_g,rgb_2_g,rgb_3_g,\
rgb_0_b,rgb_1_b,rgb_2_b,rgb_3_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,rgb_2_r_alt,rgb_3_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,rgb_2_g_alt,rgb_3_g_alt,\
rgb_0_b_alt,rgb_1_b_alt,rgb_2_b_alt,rgb_3_b_alt\
={crop(#-1)}
elif w==5
hsl_0_h,hsl_1_h,hsl_2_h,hsl_3_h,hsl_4_h,\
hsl_0_s,hsl_1_s,hsl_2_s,hsl_3_s,hsl_4_s,\
hsl_0_l,hsl_1_l,hsl_2_l,hsl_3_l,hsl_4_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,rgb_2_r,rgb_3_r,rgb_4_r,\
rgb_0_g,rgb_1_g,rgb_2_g,rgb_3_g,rgb_4_g,\
rgb_0_b,rgb_1_b,rgb_2_b,rgb_3_b,rgb_4_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,rgb_2_r_alt,rgb_3_r_alt,rgb_4_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,rgb_2_g_alt,rgb_3_g_alt,rgb_4_g_alt,\
rgb_0_b_alt,rgb_1_b_alt,rgb_2_b_alt,rgb_3_b_alt,rgb_4_b_alt\
={crop(#-1)}
elif w==6
hsl_0_h,hsl_1_h,hsl_2_h,hsl_3_h,hsl_4_h,hsl_5_h,\
hsl_0_s,hsl_1_s,hsl_2_s,hsl_3_s,hsl_4_s,hsl_5_s,\
hsl_0_l,hsl_1_l,hsl_2_l,hsl_3_l,hsl_4_l,hsl_5_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,rgb_2_r,rgb_3_r,rgb_4_r,rgb_5_r,\
rgb_0_g,rgb_1_g,rgb_2_g,rgb_3_g,rgb_4_g,rgb_5_g,\
rgb_0_b,rgb_1_b,rgb_2_b,rgb_3_b,rgb_4_b,rgb_5_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,rgb_2_r_alt,rgb_3_r_alt,rgb_4_r_alt,rgb_5_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,rgb_2_g_alt,rgb_3_g_alt,rgb_4_g_alt,rgb_5_g_alt,\
rgb_0_b_alt,rgb_1_b_alt,rgb_2_b_alt,rgb_3_b_alt,rgb_4_b_alt,rgb_5_b_alt\
={crop(#-1)}
fi
elif [${9-23}]!=[${29-46}]
eval "
vec_a=[${9-23}];
vec_b=[${29-46}];
repeat(arg(1+$5,6,6,6,2,3,3,4,3,4,5,6),p,
a=(vec_a)[3*p,3];
b=(vec_b)[3*p,3];
a!=b(
v=p;
run('col_a=',vtos(a));
run('col_b=',vtos(b));
break();
);
);
v;"
1,1,1,3,(${9-23})[3*${},3]
1,1,1,3,(${28-45})[3*${},3]
if $4
ryb2rgb[-2,-1]
rgb2hsl[-2,-1]
else
rgb2hsl[-2,-1]
fi
hsl_base={"
fmod(a)=a-360*floor(a/360);
rescale_saturation(a)=a*200-100;
rescale_lightness(a)=a*100;
new_col=crop(#-2);
old_col=crop(#-1);
diff=new_col-old_col;
diff[1]=rescale_saturation(diff[1]);
diff[2]=rescale_lightness(diff[2]);
out_hsl=[${1-3}]
out_hsl[0]+=diff[0];
out_hsl[0]=fmod(out_hsl[0]);
out_hsl[1]+=diff[1];
out_hsl[2]+=diff[2];
out_hsl[1]=cut(out_hsl[1],-100,100);
out_hsl[2]=cut(out_hsl[2],0,100);
out_hsl;
"}
+rep_color_harmony_palette $hsl_base,$5,$4
sh.. 1 *. 200 -. 100 sh... 2 *. 100 rm[-2,-1]
hsl_h,hsl_s,hsl_l={I(#-2,0)}
if w==2
hsl_0_h,hsl_1_h,\
hsl_0_s,hsl_1_s,\
hsl_0_l,hsl_1_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,\
rgb_0_g,rgb_1_g,\
rgb_0_b,rgb_1_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,\
rgb_0_b_alt,rgb_1_b_alt\
={crop(#-1)}
elif w==3
hsl_0_h,hsl_1_h,hsl_2_h,\
hsl_0_s,hsl_1_s,hsl_2_s,\
hsl_0_l,hsl_1_l,hsl_2_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,rgb_2_r,\
rgb_0_g,rgb_1_g,rgb_2_g,\
rgb_0_b,rgb_1_b,rgb_2_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,rgb_2_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,rgb_2_g_alt,\
rgb_0_b_alt,rgb_1_b_alt,rgb_2_b_alt\
={crop(#-1)}
elif w==4
hsl_0_h,hsl_1_h,hsl_2_h,hsl_3_h,\
hsl_0_s,hsl_1_s,hsl_2_s,hsl_3_s,\
hsl_0_l,hsl_1_l,hsl_2_l,hsl_3_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,rgb_2_r,rgb_3_r,\
rgb_0_g,rgb_1_g,rgb_2_g,rgb_3_g,\
rgb_0_b,rgb_1_b,rgb_2_b,rgb_3_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,rgb_2_r_alt,rgb_3_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,rgb_2_g_alt,rgb_3_g_alt,\
rgb_0_b_alt,rgb_1_b_alt,rgb_2_b_alt,rgb_3_b_alt\
={crop(#-1)}
elif w==5
hsl_0_h,hsl_1_h,hsl_2_h,hsl_3_h,hsl_4_h,\
hsl_0_s,hsl_1_s,hsl_2_s,hsl_3_s,hsl_4_s,\
hsl_0_l,hsl_1_l,hsl_2_l,hsl_3_l,hsl_4_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,rgb_2_r,rgb_3_r,rgb_4_r,\
rgb_0_g,rgb_1_g,rgb_2_g,rgb_3_g,rgb_4_g,\
rgb_0_b,rgb_1_b,rgb_2_b,rgb_3_b,rgb_4_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,rgb_2_r_alt,rgb_3_r_alt,rgb_4_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,rgb_2_g_alt,rgb_3_g_alt,rgb_4_g_alt,\
rgb_0_b_alt,rgb_1_b_alt,rgb_2_b_alt,rgb_3_b_alt,rgb_4_b_alt\
={crop(#-1)}
elif w==6
hsl_0_h,hsl_1_h,hsl_2_h,hsl_3_h,hsl_4_h,hsl_5_h,\
hsl_0_s,hsl_1_s,hsl_2_s,hsl_3_s,hsl_4_s,hsl_5_s,\
hsl_0_l,hsl_1_l,hsl_2_l,hsl_3_l,hsl_4_l,hsl_5_l\
={crop(#-2)}
rgb_0_r,rgb_1_r,rgb_2_r,rgb_3_r,rgb_4_r,rgb_5_r,\
rgb_0_g,rgb_1_g,rgb_2_g,rgb_3_g,rgb_4_g,rgb_5_g,\
rgb_0_b,rgb_1_b,rgb_2_b,rgb_3_b,rgb_4_b,rgb_5_b\
={crop(#-1)}
rgb_0_r_alt,rgb_1_r_alt,rgb_2_r_alt,rgb_3_r_alt,rgb_4_r_alt,rgb_5_r_alt,\
rgb_0_g_alt,rgb_1_g_alt,rgb_2_g_alt,rgb_3_g_alt,rgb_4_g_alt,rgb_5_g_alt,\
rgb_0_b_alt,rgb_1_b_alt,rgb_2_b_alt,rgb_3_b_alt,rgb_4_b_alt,rgb_5_b_alt\
={crop(#-1)}
fi
fi
k.
u "{$hsl_h}"\
"{$hsl_s}"\
"{$hsl_l}"\
"{$4}"\
"{$5}"\
"{$rgb_0_r,$rgb_0_g,$rgb_0_b}"\
"{$rgb_1_r,$rgb_1_g,$rgb_1_b}"\
"{$rgb_2_r,$rgb_2_g,$rgb_2_b}"\
"{$rgb_3_r,$rgb_3_g,$rgb_3_b}"\
"{$rgb_4_r,$rgb_4_g,$rgb_4_b}"\
"{$rgb_5_r,$rgb_5_g,$rgb_5_b}"\
"{$24,$25}"\
"{$26}"\
"{$27,$28}"\
"{$rgb_0_r_alt,$rgb_0_g_alt,$rgb_0_b_alt}"\
"{$rgb_1_r_alt,$rgb_1_g_alt,$rgb_1_b_alt}"\
"{$rgb_2_r_alt,$rgb_2_g_alt,$rgb_2_b_alt}"\
"{$rgb_3_r_alt,$rgb_3_g_alt,$rgb_3_b_alt}"\
"{$rgb_4_r_alt,$rgb_4_g_alt,$rgb_4_b_alt}"\
"{$rgb_5_r_alt,$rgb_5_g_alt,$rgb_5_b_alt}"\
"{$hsl_0_h}"\
"{$hsl_0_s}"\
"{$hsl_0_l}"\
"{$hsl_1_h}"\
"{$hsl_1_s}"\
"{$hsl_1_l}"\
"{$hsl_2_h}"\
"{$hsl_2_s}"\
"{$hsl_2_l}"\
"{$hsl_3_h}"\
"{$hsl_3_s}"\
"{$hsl_3_l}"\
"{$hsl_4_h}"\
"{$hsl_4_s}"\
"{$hsl_4_l}"\
"{$hsl_5_h}"\
"{$hsl_5_s}"\
"{$hsl_5_l}"\
"{$65}"\
"{$66}"\
"{$67}"\
"{$68}"\
"{$69}"\
"{$70}"
fx_rep_color_harmonies_piece:
1,1,1,2,"
const cx=(w#-1-1)/2;
const cy=(h#-1-1)/2;
const scale=2/$25%;
const ref_dist=min(w#-1,h#-1)/scale;
const point_position=ref_dist*$24%;
const rad_ang=($1+90)°;
const shade_tint=($3/100+1)/2;
const radius=lerp(point_position,ref_dist,shade_tint);
const pos_x=cos(rad_ang)*radius;
const pos_y=sin(rad_ang)*radius;
[cx+pos_x,cy-pos_y];"
rep_create_hsl_color_select:
skip ${2=.25},${3=0},${4=.9}
ow,oh={w},{h}
rm
$ow,$oh,1,3,"*begin(
const ww=w-1;
const hh=h-1;
const cx=ww/2;
const cy=hh/2;
const sd=max(w,h)/min(w,h);
const scaling=1/$4;
const sx=(w>h?sd:1)*scaling;
const sy=(w>h?1:sd)*scaling;
const cxsx=cx/sx;
const cysy=cy/sy;
const pt=$2;
const ipt=1/(1-pt);
const res_atan_end=(2*pi)/360;
const saturation=$1;
rescale_radial(a)=(a-pt)*ipt;
rescale_atan2(a)=(a+pi)/res_atan_end;
hsl2rgb(hue,saturation,lightness)=(
H=(hue/60)%6;
C=(1-abs(2*lightness-1))*saturation;
X=C*(1-abs(H%2-1));
m=lightness-C/2;
RGB=arg(1 + int(H),[C,X,0],[X,C,0],[0,C,X],[0,X,C],[X,0,C],[C,0,X]);
(RGB+=m)*=255;
);
hsl2ryb2rgb(hue,saturation,lightness)=(
H=(hue/60)%6;
C=(1-abs(2*lightness-1))*saturation;
X=C*(1-abs(H%2-1));
m=lightness-C/2;
RYB=arg(1+int(H),[C,X,0],[X,C,0],[0,C,X],[0,X,C],[X,0,C],[C,0,X]);
RYB+=m*=255;
red=RYB[0];
yellow=RYB[1];
blue=RYB[2];
white=min(RYB);
red-=white;
yellow-=white;
blue-=white;
maxyellow=max(red,yellow,blue);
green=min(yellow,blue);
yellow-=green;
blue-=green;
blue>0&&green>0?(
blue*=2;
green*=2
);
red+=yellow;
green+=yellow;
maxgreen = max(red,green,blue);
maxgreen>0?(
N=maxyellow/maxgreen;
red*=N;
green*=N;
blue*=N;
);
red+=white;
green+=white;
blue+=white;
[red,green,blue];
);
if($3
,calc(hue,saturation,lightness)=hsl2ryb2rgb(hue,saturation,lightness);
,calc(hue,saturation,lightness)=hsl2rgb(hue,saturation,lightness);
);
ev_light=vector(#3,255);
ev_dark=vector(#3,0);
);
xx=(x-cx)/cxsx;
yy=(y-cy)/cysy;
radial_gradient=rescale_radial(norm(xx,yy));
inrange(radial_gradient,0,1,1,1)?(
conical_gradient=rescale_atan2(atan2(xx,yy));
calc(conical_gradient,saturation,radial_gradient);
):(
radial_gradient>.5?ev_light:ev_dark;
);"
EDIT: I got it to work with adding " around the variable in u …
More work done on this “demo” or “concept” filter:
What this does is generate a palette based on color wheel. There’s a lot of additional GUI panels as they’re used to store temporary values for comparison purpose at the code level. I believe @grosgood might be able to benefit from this concept.
This look fun. 
It is though there’s a really strange bug. If I move the point on preview off, then preview on, the result is expected. Now, if I move the point on preview on, then the point will return always at a specified distance away from the center.
How strange is that? I’ll look into making a simplified version of this bug I seen.
Color Harmonies Code
#@cli rep_hsl2ryb2rgb
#@cli : Convert color representation of selected image from HSL to RYB to RGB
rep_hsl2ryb2rgb:
e[^-1] "Convert color representation of image$? from HSL to RYB to RGB."
f "H=(i0/60)%6;C=(1-abs(2*i2-1))*i1;X=C*(1-abs(H%2-1));
m=i2-C/2;
RYB=arg(1+int(H),[C,X,0],[X,C,0],[0,C,X],[0,X,C],[X,0,C],[C,0,X]);
RYB+=m*=255;
red=RYB[0];
yellow=RYB[1];
blue=RYB[2];
white=min(RYB);
red-=white;
yellow-=white;
blue-=white;
maxyellow=max(red,yellow,blue);
green=min(yellow,blue);
yellow-=green;
blue-=green;
blue>0&&green>0?(
blue*=2;
green*=2
);
red+=yellow;
green+=yellow;
maxgreen = max(red,green,blue);
maxgreen>0?(
N=maxyellow/maxgreen;
red*=N;
green*=N;
blue*=N;
);
red+=white;
green+=white;
blue+=white;
[red,green,blue];"
#@cli rep_color_harmony_palette: -360<=ang<=360,0<=_saturation<=1,-100[%]<=shade_tint<=100[%],0<=choice<=10,ryb_mode={ 0=rgb | 1=ryb | 2=hsl+rgb | 3=hsl+ryb }
#@cli : Create a harmony palette. In other word, create a palette based on the color wheel.
+rep_color_harmony_palette:
ang,saturation,shade_tint,choice,ryb_mode=${1-5}
{arg(1+$choice%11,6,6,6,2,3,3,4,3,4,5,6)},1,1,3,">begin(
fmod(a)=a-360*floor(a/360);
const start_ang=fmod($ang);
const saturation=cut($saturation,0,1);
const shade_tint=cut((1+$shade_tint)/2,0,1);
const choice=$choice%11;
ang=start_ang;
choice<3?( #Neutral 8-15 and Analogous 30
const add_ang=arg(choice+1,8,15,30);
new_ang()=x?(ang+=add_ang;ang=fmod(ang););
):
choice==3?( #Complementary
new_ang()=x?ang=fmod(ang+180);
):
choice==4?( #Split-Complementary
new_ang()=x==2?(ang+=60;ang=fmod(ang);):x==1?(ang+=150;ang=fmod(ang););
):
choice==5?( #Triadic
new_ang()=x?ang=fmod(ang+120);
):
choice==6?( #Tetradic
new_ang()=x?ang=fmod(ang+90);
):
choice==7?( #Clash
new_ang()=x?(ang=fmod(start_ang+(x%2?90:-90)));
):
choice==8?( #Four Tones
new_ang()=x?(ang=fmod(ang+arg(x%2+1,120,60)););
):
choice==9?( #Five Tones
new_ang()=x?(x==1?(ang=fmod(ang+120);):(ang=fmod(ang+arg(x%2+1,30,60))););
):( #Six Tones
new_ang()=x?(ang=fmod(ang+(x%2?30:90)););
);
);
new_ang();
[ang,saturation,shade_tint];"
if $ryb_mode>1
if $ryb_mode%2 +rep_hsl2ryb2rgb. else +hsl2rgb. fi
else
if $ryb_mode rep_hsl2ryb2rgb. else hsl2rgb. fi
fi
round.
#@gui Color Harmonies: fx_rep_color_harmonies
#@gui :_=separator(),_=note("<b>Reference Point</b>")
#@gui :1.Hue=float(50,0,360)
#@gui :2.Saturation(%)=float(100,0,100)
#@gui :3.Shade/Tint(%)=float(0,-100,100)
#@gui :4.Color Space=choice(0,"RGB",RYB")
#@gui :_=separator(),_=note("<b>Additional Information</b>")
#@gui :5.Palette Mode=choice(0,"Neutral 8","Neutral 15","Analogous 30","Complementary","Split-Complementary","Triadic","Tetradic","Clash","Four Tones","Five Tones","Six Tones")
#@gui :_=separator(),_=note("<b>Output Color</b>")
#@gui :6.7.8. Color A=color(0,0,0)
#@gui :9.10.11. Color B=color(0,0,0)
#@gui :12.13.14.Color C=color(0,0,0)
#@gui :15.16.17.Color D=color(0,0,0)
#@gui :18.19.20.Color E=color(0,0,0)
#@gui :21.22.23.Color F=color(0,0,0)
#@gui :_=separator(),_=note("<b>Preview</b>")
#@gui :24.25.Color Point Position=point(50,50,0,1,128,128,128,255)
#@gui :26.Color Select Position(%)=float(10,10,50)
#@gui :27.Scaling(%)=float(90,30,100)
#@gui :28.29.Point-X=point(50,50,0,0,0,0,0,0,0)
#@gui :30.31.32.Color A=color(0,0,0)
#@gui :33.34.35.Color B=color(0,0,0)
#@gui :36.37.38.Color C=color(0,0,0)
#@gui :39.40.41.Color D=color(0,0,0)
#@gui :42.43.44.Color E=color(0,0,0)
#@gui :45.46.47.Color F=color(0,0,0)
#@gui :48a.Hue=float(0,0,360)
#@gui :49a.Saturation(%)=float(100,0,100)
#@gui :50a.Shade/Tint(%)=float(0,-100,100)
#@gui :51b.Hue=float(0,0,360)
#@gui :52b.Saturation(%)=float(100,0,100)
#@gui :53b.Shade/Tint(%)=float(0,-100,100)
#@gui :54c.Hue=float(0,0,360)
#@gui :55c.Saturation(%)=float(100,0,100)
#@gui :56c.Shade/Tint(%)=float(0,-100,100)
#@gui :57d.Hue=float(0,0,360)
#@gui :58d.Saturation(%)=float(100,0,100)
#@gui :59d.Shade/Tint(%)=float(0,-100,100)
#@gui :60e.Hue=float(0,0,360)
#@gui :61e.Saturation(%)=float(100,0,100)
#@gui :62e.Shade/Tint(%)=float(0,-100,100)
#@gui :63f.Hue=float(0,0,360)
#@gui :64f.Saturation(%)=float(100,0,100)
#@gui :65f.Shade/Tint(%)=float(0,-100,100)
#@gui :66.Color Space=choice(0,"RGB",RYB")
#@gui :67.Palette Mode=choice(0,"Neutral 8","Neutral 15","Analogous 30","Complementary","Split-Complementary","Triadic","Tetradic","Clash","Four Tones","Five Tones","Six Tones")
#@gui :68.Color Select Position(%)=float(10,10,50)
#@gui :69.Scaling(%)=float(90,30,100)
#@gui :70.Preview Palette?=bool(0)
#@gui :71.Orientation=choice(0,"Horizontal","Vertical")
#@gui :72.Palette X=choice(1,"Bottom","Middle","Top")
#@gui :73.Palette Y=choice(1,"Left","Middle","Top")
fx_rep_color_harmonies:
_hsl_h,_hsl_s,_hsl_l,\
_rgb_0_r,_rgb_0_g,_rgb_0_b,\
_rgb_1_r,_rgb_1_g,_rgb_1_b,\
_rgb_2_r,_rgb_2_g,_rgb_2_b,\
_rgb_3_r,_rgb_3_g,_rgb_3_b,\
_rgb_4_r,_rgb_4_g,_rgb_4_b,\
_rgb_5_r,_rgb_5_g,_rgb_5_b,\
_rgb_0_r_alt,_rgb_0_g_alt,_rgb_0_b_alt,\
_rgb_1_r_alt,_rgb_1_g_alt,_rgb_1_b_alt,\
_rgb_2_r_alt,_rgb_2_g_alt,_rgb_2_b_alt,\
_rgb_3_r_alt,_rgb_3_g_alt,_rgb_3_b_alt,\
_rgb_4_r_alt,_rgb_4_g_alt,_rgb_4_b_alt,\
_rgb_5_r_alt,_rgb_5_g_alt,_rgb_5_b_alt,\
_hsl_0_h,_hsl_0_s,_hsl_0_l,\
_hsl_1_h,_hsl_1_s,_hsl_1_l,\
_hsl_2_h,_hsl_2_s,_hsl_2_l,\
_hsl_3_h,_hsl_3_s,_hsl_3_l,\
_hsl_4_h,_hsl_4_s,_hsl_4_l,\
_hsl_5_h,_hsl_5_s,_hsl_5_l,\
_point_x_0,_point_y_0\
=${1-3},${6-23},${30-65},$24,$25
m "draw_points :
eval[1] \"begin(
const radius=9;
const colsize=sqr(radius)*3;
blkcol=vector(#colsize,128);
circle_alpha_component=expr('begin(
const ww=w-1;
const hh=h-1;
const cx=ww/2;
const cy=hh/2;
);
xx=(x-cx)/cx;
yy=(y-cy)/cy;
inrange(norm(xx,yy),.4,1,1);'
,radius,radius,1,1);
);
m=(I/100)*[w#0,h#0];
if(x,
draw(#0,blkcol,round(m[0])-6,round(m[1])-6,0,0,radius,radius,1,3,1,circle_alpha_component,1);
);
\"
"
m "gen_pt_info :
width,height={w#0},{h#0}
l..
lightness={i(#-1,0,0,0,2)}
{w},{h},{d},2,\"begin(
const scale=$27%;
const lightness=($lightness+100)/200;
const width=$width;
const height=$height;
const ww=width-1;
const hh=height-1;
const cx=ww/2;
const cy=hh/2;
const ref_dim=min(cx,cy);
const max_length=ref_dim*scale;
const min_length=max_length*$26/100;
const length=lerp(min_length,max_length,lightness);
);
rad_ang=((360-i(#-1,x,0,0,0))-90)°;
center=[cx,cy];
off=[cos(rad_ang)*length,sin(rad_ang)*length];
point=center+off;
point[0]/=ww;
point[1]/=hh;
point*=100;\"
_point_x_0,_point_y_0={I(#-1,0)}
rv
endl
draw_points "
# Below, I had to provide a workaround for point-location change
m "gen_pt_info_alt :
width,height={w#0},{h#0}
l..
{w},{h},{d},2,\"begin(
const scale=$27%;
const width=$width;
const height=$height;
const mx=width-1;
const my=height-1;
const cx=mx/2;
const cy=my/2;
const ref_dim=min(cx,cy);
const max_length=ref_dim*scale;
const min_length=max_length*$26/100;
const pos_x=mx*$24/100;
const pos_y=my*$25/100;
const dx=pos_x-cx;
const dy=pos_y-cy;
const dist=cut(sqrt(dx^2+dy^2),min_length,max_length);
);
rad_ang=((360-i(#-1,x,0,0,0))-90)°;
center=[cx,cy];
off=[cos(rad_ang)*dist,sin(rad_ang)*dist];
point=center+off;
point[0]/=mx;
point[1]/=my;
point*=100;\"
_point_x_0,_point_y_0=$24,$25
rv
endl
draw_points "
m "gen_col_info :
if w==2
_hsl_0_h,_hsl_1_h,\
_hsl_0_s,_hsl_1_s,\
_hsl_0_l,_hsl_1_l\
={crop(#-2)}
_rgb_0_r,_rgb_1_r,\
_rgb_0_g,_rgb_1_g,\
_rgb_0_b,_rgb_1_b\
={crop(#-1)}
_rgb_0_r_alt,_rgb_1_r_alt,\
_rgb_0_g_alt,_rgb_1_g_alt,\
_rgb_0_b_alt,_rgb_1_b_alt\
={crop(#-1)}
elif w==3
_hsl_0_h,_hsl_1_h,_hsl_2_h,\
_hsl_0_s,_hsl_1_s,_hsl_2_s,\
_hsl_0_l,_hsl_1_l,_hsl_2_l\
={crop(#-2)}
_rgb_0_r,_rgb_1_r,_rgb_2_r,\
_rgb_0_g,_rgb_1_g,_rgb_2_g,\
_rgb_0_b,_rgb_1_b,_rgb_2_b\
={crop(#-1)}
_rgb_0_r_alt,_rgb_1_r_alt,_rgb_2_r_alt,\
_rgb_0_g_alt,_rgb_1_g_alt,_rgb_2_g_alt,\
_rgb_0_b_alt,_rgb_1_b_alt,_rgb_2_b_alt\
={crop(#-1)}
elif w==4
_hsl_0_h,_hsl_1_h,_hsl_2_h,_hsl_3_h,\
_hsl_0_s,_hsl_1_s,_hsl_2_s,_hsl_3_s,\
_hsl_0_l,_hsl_1_l,_hsl_2_l,_hsl_3_l\
={crop(#-2)}
_rgb_0_r,_rgb_1_r,_rgb_2_r,_rgb_3_r,\
_rgb_0_g,_rgb_1_g,_rgb_2_g,_rgb_3_g,\
_rgb_0_b,_rgb_1_b,_rgb_2_b,_rgb_3_b\
={crop(#-1)}
_rgb_0_r_alt,_rgb_1_r_alt,_rgb_2_r_alt,_rgb_3_r_alt,\
_rgb_0_g_alt,_rgb_1_g_alt,_rgb_2_g_alt,_rgb_3_g_alt,\
_rgb_0_b_alt,_rgb_1_b_alt,_rgb_2_b_alt,_rgb_3_b_alt\
={crop(#-1)}
elif w==5
_hsl_0_h,_hsl_1_h,_hsl_2_h,_hsl_3_h,_hsl_4_h,\
_hsl_0_s,_hsl_1_s,_hsl_2_s,_hsl_3_s,_hsl_4_s,\
_hsl_0_l,_hsl_1_l,_hsl_2_l,_hsl_3_l,_hsl_4_l\
={crop(#-2)}
_rgb_0_r,_rgb_1_r,_rgb_2_r,_rgb_3_r,_rgb_4_r,\
_rgb_0_g,_rgb_1_g,_rgb_2_g,_rgb_3_g,_rgb_4_g,\
_rgb_0_b,_rgb_1_b,_rgb_2_b,_rgb_3_b,_rgb_4_b\
={crop(#-1)}
_rgb_0_r_alt,_rgb_1_r_alt,_rgb_2_r_alt,_rgb_3_r_alt,_rgb_4_r_alt,\
_rgb_0_g_alt,_rgb_1_g_alt,_rgb_2_g_alt,_rgb_3_g_alt,_rgb_4_g_alt,\
_rgb_0_b_alt,_rgb_1_b_alt,_rgb_2_b_alt,_rgb_3_b_alt,_rgb_4_b_alt\
={crop(#-1)}
elif w==6
_hsl_0_h,_hsl_1_h,_hsl_2_h,_hsl_3_h,_hsl_4_h,_hsl_5_h,\
_hsl_0_s,_hsl_1_s,_hsl_2_s,_hsl_3_s,_hsl_4_s,_hsl_5_s,\
_hsl_0_l,_hsl_1_l,_hsl_2_l,_hsl_3_l,_hsl_4_l,_hsl_5_l\
={crop(#-2)}
_rgb_0_r,_rgb_1_r,_rgb_2_r,_rgb_3_r,_rgb_4_r,_rgb_5_r,\
_rgb_0_g,_rgb_1_g,_rgb_2_g,_rgb_3_g,_rgb_4_g,_rgb_5_g,\
_rgb_0_b,_rgb_1_b,_rgb_2_b,_rgb_3_b,_rgb_4_b,_rgb_5_b\
={crop(#-1)}
_rgb_0_r_alt,_rgb_1_r_alt,_rgb_2_r_alt,_rgb_3_r_alt,_rgb_4_r_alt,_rgb_5_r_alt,\
_rgb_0_g_alt,_rgb_1_g_alt,_rgb_2_g_alt,_rgb_3_g_alt,_rgb_4_g_alt,_rgb_5_g_alt,\
_rgb_0_b_alt,_rgb_1_b_alt,_rgb_2_b_alt,_rgb_3_b_alt,_rgb_4_b_alt,_rgb_5_b_alt\
={crop(#-1)}
fi"
if ([${1-3}]!=[${48-50}])||($4!=$66)||($5!=$67)
rep_create_hsl_color_select $2%,{$26/100},$4,{$27/100}
+rep_color_harmony_palette $1,{$2/100},{$3/100},$5,{$4+2}
sh.. 2 *. 200 -. 100 sh... 1 *. 100 rm[-2,-1]
gen_col_info gen_pt_info
elif [${6-23}]!=[${30-47}]
eval "
vec_a=[${6-23}];
vec_b=[${30-47}];
repeat(arg(1+$5,6,6,6,2,3,3,4,3,4,5,6),p,
a=(vec_a)[3*p,3];
b=(vec_b)[3*p,3];
a!=b?(
v=p;
run('col_a=',vtos(a));
run('col_b=',vtos(b));
break();
);
);
v;"
1,1,1,3,([${6-23}])[3*${},3]
1,1,1,3,([${30-47}])[3*${},3]
if $4
rgb2ryb[-2,-1]
rgb2hsl[-2,-1]
else
rgb2hsl[-2,-1]
fi
hsl_base={"
fmod(a)=a-360*floor(a/360);
rescale_lightness(a)=(a+100)/200;
new_col=crop(#-2);
old_col=crop(#-1);
diff=new_col-old_col;
out_hsl=[${1-3}];
out_hsl[1]/=100;
out_hsl[2]=rescale_lightness(out_hsl[2]);
out_hsl+=diff;
out_hsl[2]=cut(out_hsl[2]*2-1,-1,1);
out_hsl[1]=cut(out_hsl[1],0,1);
out_hsl;
"}
rep_create_hsl_color_select {arg(2,$hsl_base)},{$26/100},$4,{$27/100}
+rep_color_harmony_palette $hsl_base,$5,{$4+2}
sh.. 2 *. 200 -. 100 sh... 1 *. 100 rm[-2,-1]
_hsl_h,_hsl_s,_hsl_l={I(#-2,0)}
gen_col_info gen_pt_info
elif [${24-25}]!=[${28-29}]
rep_create_hsl_color_select $2%,{$26/100},$4,{$27/100}
hsl_base={"
const scale=$27%;
const mx=w-1;
const my=h-1;
const cx=mx/2;
const cy=my/2;
const ref_dim=min(cx,cy);
const max_length=ref_dim*scale;
const min_length=max_length*$26/100;
const length=max_length-min_length;
const pos_x=mx*$24%;
const pos_y=my*$25%;
const dx=pos_x-cx;
const dy=pos_y-cy;
const hue=(atan2(dx,dy)+pi)/((pi*2)/360);
const dist=2*((cut(sqrt(dx^2+dy^2),min_length,max_length)-min_length)/length)-1;
[hue,$2/100,dist];
"}
+rep_color_harmony_palette $hsl_base,$5,{$4+2}
sh.. 2 *. 200 -. 100 sh... 1 *. 100 rm[-2,-1]
_hsl_h,_hsl_s,_hsl_l={I(#-2,0)}
gen_col_info gen_pt_info_alt
else
rep_create_hsl_color_select $2%,{$26/100},$4,{$27/100}
+rep_color_harmony_palette $1,{$2/100},{$3/100},$5,{$4+2}
gen_pt_info
fi
u "{"$_hsl_h"}"\
"{"$_hsl_s"}"\
"{"$_hsl_l"}"\
"{$4}"\
"{$5}"\
"{"$_rgb_0_r","$_rgb_0_g","$_rgb_0_b"}"\
"{"$_rgb_1_r","$_rgb_1_g","$_rgb_1_b"}"\
"{"$_rgb_2_r","$_rgb_2_g","$_rgb_2_b"}"\
"{"$_rgb_3_r","$_rgb_3_g","$_rgb_3_b"}"\
"{"$_rgb_4_r","$_rgb_4_g","$_rgb_4_b"}"\
"{"$_rgb_5_r","$_rgb_5_g","$_rgb_5_b"}"\
"{"$_point_x_0","$_point_y_0"}"\
"{$26}"\
"{$27}"\
"{"$_point_x_0","$_point_y_0"}"\
"{"$_rgb_0_r_alt","$_rgb_0_g_alt","$_rgb_0_b_alt"}"\
"{"$_rgb_1_r_alt","$_rgb_1_g_alt","$_rgb_1_b_alt"}"\
"{"$_rgb_2_r_alt","$_rgb_2_g_alt","$_rgb_2_b_alt"}"\
"{"$_rgb_3_r_alt","$_rgb_3_g_alt","$_rgb_3_b_alt"}"\
"{"$_rgb_4_r_alt","$_rgb_4_g_alt","$_rgb_4_b_alt"}"\
"{"$_rgb_5_r_alt","$_rgb_5_g_alt","$_rgb_5_b_alt"}"\
"{"$_hsl_0_h"}"\
"{"$_hsl_0_s"}"\
"{"$_hsl_0_l"}"\
"{"$_hsl_1_h"}"\
"{"$_hsl_1_s"}"\
"{"$_hsl_1_l"}"\
"{"$_hsl_2_h"}"\
"{"$_hsl_2_s"}"\
"{"$_hsl_2_l"}"\
"{"$_hsl_3_h"}"\
"{"$_hsl_3_s"}"\
"{"$_hsl_3_l"}"\
"{"$_hsl_4_h"}"\
"{"$_hsl_4_s"}"\
"{"$_hsl_4_l"}"\
"{"$_hsl_5_h"}"\
"{"$_hsl_5_s"}"\
"{"$_hsl_5_l"}"\
"{$4}"\
"{$5}"\
"{$26}"\
"{$27}"\
"{$70}"\
"{$71}"\
"{$72}"\
"{$73}"
rep_create_hsl_color_select:
skip ${2=.25},${3=0},${4=.9}
ow,oh={w#0},{h#0}
rm
$ow,$oh,1,3,"*begin(
const ww=w-1;
const hh=h-1;
const cx=ww/2;
const cy=hh/2;
const sd=max(w,h)/min(w,h);
const scaling=1/$4;
const sx=(w>h?sd:1)*scaling;
const sy=(w>h?1:sd)*scaling;
const cxsx=cx/sx;
const cysy=cy/sy;
const pt=$2;
const ipt=1/(1-pt);
const res_atan_end=(2*pi)/360;
const saturation=$1;
rescale_radial(a)=(a-pt)*ipt;
rescale_atan2(a)=(a+pi)/res_atan_end;
hsl2rgb(hue,saturation,lightness)=(
H=(hue/60)%6;
C=(1-abs(2*lightness-1))*saturation;
X=C*(1-abs(H%2-1));
m=lightness-C/2;
RGB=arg(1 + int(H),[C,X,0],[X,C,0],[0,C,X],[0,X,C],[X,0,C],[C,0,X]);
(RGB+=m)*=255;
);
hsl2ryb2rgb(hue,saturation,lightness)=(
H=(hue/60)%6;
C=(1-abs(2*lightness-1))*saturation;
X=C*(1-abs(H%2-1));
m=lightness-C/2;
RYB=arg(1+int(H),[C,X,0],[X,C,0],[0,C,X],[0,X,C],[X,0,C],[C,0,X]);
RYB+=m*=255;
red=RYB[0];
yellow=RYB[1];
blue=RYB[2];
white=min(RYB);
red-=white;
yellow-=white;
blue-=white;
maxyellow=max(red,yellow,blue);
green=min(yellow,blue);
yellow-=green;
blue-=green;
blue>0&&green>0?(
blue*=2;
green*=2
);
red+=yellow;
green+=yellow;
maxgreen = max(red,green,blue);
maxgreen>0?(
N=maxyellow/maxgreen;
red*=N;
green*=N;
blue*=N;
);
red+=white;
green+=white;
blue+=white;
[red,green,blue];
);
if($3
,calc(hue,saturation,lightness)=hsl2ryb2rgb(hue,saturation,lightness);
,calc(hue,saturation,lightness)=hsl2rgb(hue,saturation,lightness);
);
ev_light=vector(#3,255);
ev_dark=vector(#3,0);
);
xx=(x-cx)/cxsx;
yy=(y-cy)/cysy;
radial_gradient=rescale_radial(norm(xx,yy));
inrange(radial_gradient,0,1,1,1)?(
conical_gradient=rescale_atan2(atan2(xx,yy));
calc(conical_gradient,saturation,radial_gradient);
):(
radial_gradient>.5?ev_light:ev_dark;
);"
EDIT: I pushed it, but it will remain a demo filter as long as that strange bug can’t be resolved.
Maybe use display instead of the plugin as a workaround… but that would be kind of annoying.
Indeed…
Now I’m in the process of trying to remember how I optimized Fragment Blur, but all results points to the current code being the fastest approach. Any idea? I remember once testing generating a string with multiple Js inside fill function, but I tested that, and it is so much slower. It’s not the generation of string that’s slow. It’s the processing of J in math evaluator that is slow. Maybe this is a filter that should be converted with C++ in mind. shift command adds more information than I’d like, and a theoretical fast J would solve this problem.
git is your friend (use your path in this example, not mine…).
$ git log --author=reptillia39 -L 8828,8882:/home/gosgood/git_repositories/gmic-community/include/reptorian.gmic
enumerates diffs for commits which intersect with the region encompassed by lines 8828→8882 inclusive of reptorian.gmic, as it is in HEAD, a collection of intermediary differences which way-backs to that lovely spring day: Friday April 19 18:07:02 2019, -0400. I have no idea what I was doing at that moment, but @Reptorian was committing the very first bits of rep_frblur and friends. Perhaps commit 0c6b7d56bd12 on Sep. 26 2019 seems interesting. Then you might:
$ git branch bigseprewrite 0c6b7d56bd12
$ git checkout bigseprewrite
and browse around your module as it was on September 26, 2019. If you do not introduce new changes on the bigseprewrite branch, you can clean up:
git checkout master
git branch -d bigseprewrite
If, in checking out bigseprewrite you get an error:
error: Your local changes to the following files would be overwritten by checkout:
tutorial/controlf/check.gmd
Please commit your changes or stash them before you switch branches.
Then commit or stash your current uncommitted changes so that your working tree is clean and up to date.
Hope you will find the diffs to jog your memory.
I don’t recall any past commits prior to that time that would help me get to the answer. That’s the problem. It was after that time. It is entirely possible that I end up with the current code instead after concluding that multiple Js within fill wouldn’t work. Turns out that my recent experiments supports this idea.
Do you mean image when you say j ? As in:
gmic run "sp rooster +f 0 repeat 50 j. [0],{[w*u-w/2,h*u-h/2]},0,0,0.1 done"
That seems fast on my machine…
I was thinking of fill “I/J”, but that’s another idea to try. Hopefully, it’ll work out as a faster version of Fragment Blur though I doubt it due to how opacity works.
It could be a good way, remember that you can also use a mask with it (e.g. a gaussian):
gmic run "sp rooster +gaussian. 100 +f. 0 repeat 50 j. [0],{[w*u-w/2,h*u-h/2]},0,0,0.1,[1] done"
Also, if J[] and so on is slow inside a fill or eval, it’s probably not the J[] itself, it will be the underlying algorithm to blame! Use usual optimisation tricks… make your loops contain as little as possible etc.

