Some Python-Based script to make G'MIC scripting easier

I have decided to learn Python a bit to aid in speeding up coding in the G’MIC language, but I want to share these script.

These scripts utilize your clipboard, so all you need to do is copy your g’mic code snip and then execute script, and finally you will see the output.

Find Unique Arguments in dynamic gui arguments
import pyperclip as pc
import re
import numpy as np

# Copy u lines used for dynamic gui before executing!
# This file is to output all unique end arguments in u {$1}\.... series

def listToString(s):
    str1=""
    
    for ele in s:
        str1+=ele
    return str1

gmic_str_paste=pc.paste()
gmic_str=str(gmic_str_paste)
Lines=gmic_str.splitlines()

string_element=[]

for t in Lines:
    current_string=t.split('"')
    if len(current_string)==3:
        bracket_str=current_string[2]
        if len(bracket_str)>2:
            extracted_str=re.findall(r'\{.*?\}', bracket_str)
            string_element.append(str(extracted_str))

uniq_set=set([element for element in string_element if string_element.count(element)>1])
arr_uniq_set=list(uniq_set)

ordered_element=[]
position=[]

for i in arr_uniq_set:
    set_str=str(i)
    m=0
    for j in string_element:
        m=m+1
        if i==j:
            break
    position.append(m)
    
position.sort()

for i in position:
    ordered_element.append(string_element[i])
    
result=str(ordered_element)

result=re.sub('\[','',result)
result=re.sub(']','',result)
result=re.sub('\"','',result)
result=re.sub('\'','',result)
result=re.sub(' ','',result)
result=re.sub(',','',result)

print(result)
Increment all numbers next to '$'
import pyperclip as pc

#Copy codes contain $number before executing!

a = pc.paste()
sa=str(a)
b=""
tn=''

temp_num=0
increment_num=int(input("Insert Number: "))
max_num=int(input("Increment Number Equal or Greater than: "))

print('')

skip_digit=bool(True)

p=0
q=1
for c in sa:
    if c=='$':
        b=b+c
        skip_digit=bool(True)
        if a[p+q].isdigit():
            while a[p+q].isdigit():
                tn=tn+a[p+q]
                q=q+1
            if int(tn) >= max_num:
                temp_num=int(tn)+increment_num
            else:
                temp_num=int(tn)
            b=b+str(temp_num)
            tn=""
            q=1
    else:
        if not c.isdigit():
            skip_digit=bool(False)
        if c.isdigit():
            if not skip_digit:
                b=b+c
        else:
            b=b+c
    p=p+1
print(b)
Replace if,elif statement with arg-style code
import pyperclip as pc

#Copy just the if elif portion of your code before executing!

a = pc.paste()
sa=str(a)
vs=sa.splitlines()
b=[]
m=bool(False)

for c in vs:
    init_pos=c.find("if ")+2
    if init_pos!=-1 or test_end!=-1:
        end_pos=len(c)
        cut_after_if=c[init_pos:end_pos:1]
        start_eq_pos=cut_after_if.find("==")
        if start_eq_pos != -1:
            eq_string=cut_after_if[start_eq_pos:len(cut_after_if):1]
            space_string_pos=eq_string.find(" ")
            if space_string_pos != -1:
                after_init_space=eq_string[space_string_pos:len(eq_string):1]
                append_str=after_init_space.lstrip()
                b.append(append_str)
        else:
            m=bool(True)
            print("Invalid!")
            break            
    else:
        m=bool(True)
        print("Invalid!")
        break
    
if not m:
    init_end_str=""
    for i in b:
        init_end_str=init_end_str+i+","
    init_end_str=init_end_str[0:len(init_end_str)-1:1]
    print("Replace $existing_variable with a existing variable to make it work.\n")
    print("${arg\ $existing_variable,"+init_end_str+"}")

I had improve 'Increment all numbers next to ‘$’. Now, you can define which numbers equal to or greater than to increment. This is much easier than manual edit. :slight_smile:

When you write a command with a lot of arguments, a good practice is to name them before everything else, then use only the named arguments later in the code, so you are sure you won’t miss something. And you finally add a new argument in your command, it’s not a problem, you’ll be able to insert it at any place you want.

For instance:

foo :  skip "${1=0},${2=10},${3=xy}"
  smoothness,sharpness,axes=${1-3}
  blur $smoothness
  sharpen $sharpness
  mirror $axes

Now imagine I want to insert a new argument angle just before axes, then I only had to complete the two first lines of code and eventually add a few new lines, but I don’t have to “shift” the argument numbers in all lines of code that would need it:

foo : skip "${1=0},${2=10},${3=0},${4=xy}"
  smoothness,sharpness,angle,axes=${1-4}
  blur $smoothness
  sharpen $sharpness
  rotate $angle
  mirror $axes
1 Like

I wish I can edit my old post, but I made a script to automatically number the gui elements. Now, I’ll have to figure out how to do the reverse. To use this, of course, you have to use clipboard.

EDIT: I added reverse mode. You have to type in the mode that you want and press enter.

Number the GUI arguments
import pyperclip as pc
import re

num=0
u_string="u "

def find_num_of_colors(istr):
    n=1
    for c in istr:
       if c==",":
           n += 1
    return n

def new_string(istr,line):
    global num
    global u_string
    if istr in ["int","float","choice","button","text","bool"]:
        num += 1
        part_string = str(num) + "."
        if istr=="button":
            u_string += "\"{0}\"\\" + "\n"
        else:
            u_string += "\"{$"+str(num)+"}\"\\"+"\n"
        new_string = line[:7] + part_string + line[7:]
        return new_string
    elif istr=="color":
        if find_num_of_colors(line)==4:
            u_string += "\"{$" + str(int(num+1)) +",$" + str(int(num+2)) + ",$" + str(int(num+3)) + ",$" + str(int(num+4)) + "}\"\\" + "\n"
            part_string=str(int(num+1)) + "." + str(int(num+2)) + "." +str(int(num+3)) + "." + str(int(num+4)) + "."
            num += 4
            new_string=line[:7]+part_string+line[7:]
            return new_string
        else:
            u_string += "\"{$" + str(int(num+1)) +",$" + str(int(num+2)) + ",$" + str(int(num+3))  + "}\"\\" + "\n"
            part_string=str(int(num+1))+"."+str(int(num+2))+"."+str(int(num+3)) + "."
            num += 3
            new_string=line[:7]+part_string+line[7:]
            return new_string
    elif istr=="point":
        u_string += "\"{$" + str(int(num + 1)) + ",$" + str(int(num + 2))  + "}\"\\" + "\n"
        part_string = str(int(num + 1)) + "." + str(int(num + 2)) + "."
        num += 2
        new_string=line[:7]+part_string+line[7:]
        return new_string
    else:
        return line
def remove_number_and_period(line):
    pos=8
    iter=False
    while True:
        if line[pos].isdigit() or line[pos]=='.':
            iter=True
            pos += 1
        else:
            break
    if iter:
        return line[:7]+line[pos:]
    else:
        return line

between_these_char="\=(.*?)\("

gmic_str_paste=pc.paste()
gmic_str=str(gmic_str_paste)
lines=gmic_str.splitlines()

while True:
    init_mode=input("""
    Type in the one of the two characters in the set of two character at the left to use one of those mode?
    0F. Remove Number and Period. 
    1T. Add Numbers and Period0 """)
    if init_mode=="0" or init_mode=="F":
        mode=False
        break
    elif init_mode=="1" or init_mode=="T":
        mode=True
        break

if mode:
    for line in lines:
        try:
            substring=re.search(between_these_char,line).group(1)
        except AttributeError:
            substring=re.search(between_these_char,line)
        if substring is None:
            print(line)
            continue
        else:
            print(new_string(str(substring),line))

    print(u_string)
else:
    for line in lines:
        print(remove_number_and_period(line))
Old
#@gui Mitchell Concatenation: fx_rep_mitchell_concatenation
#@gui :_=note("This filter is a recreation of Kerry's Mitchell Concatenation"),_=separator()
#@gui :_=note("<b>Initial</b>")
#@gui :Mode=choice(0,"Singular","Dual")
#@gui :Pixel Size(%)=float(0,0,100)
#@gui :Output=choice(0,"New Dimension","New Dimension - New Layer","Old Dimension","Old Dimension - New Layer")
#@gui :_=separator(),_=note("<b>Starting Point</b>")
#@gui :Start=int(1,1,2000000)
#@gui :Start A=int(1,1,2000000)
#@gui :Start B=int(1,1,2000000)
#@gui :Link Start Numbers?=bool(0)
#@gui :_=separator(),_=note("<b>Base System</b>")
#@gui :Base=int(10,2,1000)
#@gui :Base A=int(10,2,1000)
#@gui :Base B=int(10,2,1000)
#@gui :Link Start Numbers?=bool(0)
#@gui :_=separator(),_=note("<b>Method</b>")
#@gui :Method=choice(0,"Subtraction","Addition","Multiplication")
#@gui :Method A=choice(0,"Subtraction","Addition","Multiplication")
#@gui :Method B=choice(0,"Subtraction","Addition","Multiplication")
#@gui :Link Start Numbers?=bool(0)
#@gui :_=separator(),_=note("<b>Palette</b>")
#@gui :Mode=choice(1,"Singular","Dual")
#@gui :Set=choice(0,"Foreground","Background")
#@gui :Color 1=color(255,255,255)
#@gui :Color 2=color(255,255,255)
#@gui :Color 3=color(255,255,255)
#@gui :Color 4=color(255,255,255)
#@gui :Color 5=color(255,255,255)
#@gui :Color 6=color(255,255,255)
#@gui :Color 7=color(255,255,255)
#@gui :Color 1=color(255,255,255)
#@gui :Color 2=color(255,255,255)
#@gui :Color 3=color(255,255,255)
#@gui :Color 4=color(255,255,255)
#@gui :Color 5=color(255,255,255)
#@gui :Color 6=color(255,255,255)
#@gui :Color 7=color(255,255,255)
#@gui :Color 1=color(255,255,255)
#@gui :Color 2=color(255,255,255)
#@gui :Color 3=color(255,255,255)
#@gui :Color 4=color(255,255,255)
#@gui :Color 5=color(255,255,255)
#@gui :Color 6=color(255,255,255)
#@gui :Color 7=color(255,255,255)
#@gui :_=separator(),_=note("<b>Shape</b>")
#@gui :Use Shape=bool(1)
#@gui :Tiled Shape=choice(3,"By Layer","Australia","Barbedwire","Circle","Crosshair","Cupid","Diamond","Dragon Curve-[D]","Dragonfly","Fern-[D]","Flip","Gear-[D]","Gumleaf","Heart","Information","Kookaburra","Mail","Mapleleaf","Paint Splat","Paw","Phone","Polygon-[D]","Rooster","Shopping Cart","Snowflake-[D]","Star-[D]")
#@gui :Fit Tile?=bool(1)
#@gui :Dragon Curve Recursion=int(10,0,30)
#@gui :Dragon Curve Rotation=float(0,-180,180)
#@gui :Fern Type=choice("Asplenium Adiantum-Nigrum","Thelypteridaceae")
#@gui :Fern Density (%)=float(100,0,300)
#@gui :Gear Teeth Count=int(8,3,32)
#@gui :Gear Height (%)=float(25,0.1,100)
#@gui :Gear Offset Teeth (%)=float(0,0,100)
#@gui :Gear Inner Ratio (%)=float(50,0.1,100)
#@gui :Polygon Vertices=int(5,3,100)
#@gui :Snowflake Recursion=int(5,1,6)
#@gui :Star Branches=int(3,5,100)
#@gui :Star Thickness (%)=float(38,.1,100)
#@gui :_=separator(),_=note("<b>Misc</b>")
#@gui :Position=choice(0,"10","100","1000","10000","100000")
#@gui :Position A=choice(0,"10","100","1000","10000","100000")
#@gui :Position B=choice(0,"10","100","1000","10000","100000")
#@gui :Push into Start Number=button()
#@gui :Push into Start A=button()
#@gui :Push into Start B=button()
#@gui :Push into Both=button()
New
#@gui Mitchell Concatenation: fx_rep_mitchell_concatenation
#@gui :_=note("This filter is a recreation of Kerry's Mitchell Concatenation"),_=separator()
#@gui :_=note("<b>Initial</b>")
#@gui :1.Mode=choice(0,"Singular","Dual")
#@gui :2.Pixel Size(%)=float(0,0,100)
#@gui :3.Output=choice(0,"New Dimension","New Dimension - New Layer","Old Dimension","Old Dimension - New Layer")
#@gui :_=separator(),_=note("<b>Starting Point</b>")
#@gui :4.Start=int(1,1,2000000)
#@gui :5.Start A=int(1,1,2000000)
#@gui :6.Start B=int(1,1,2000000)
#@gui :7.Link Start Numbers?=bool(0)
#@gui :_=separator(),_=note("<b>Base System</b>")
#@gui :8.Base=int(10,2,1000)
#@gui :9.Base A=int(10,2,1000)
#@gui :10.Base B=int(10,2,1000)
#@gui :11.Link Start Numbers?=bool(0)
#@gui :_=separator(),_=note("<b>Method</b>")
#@gui :12.Method=choice(0,"Subtraction","Addition","Multiplication")
#@gui :13.Method A=choice(0,"Subtraction","Addition","Multiplication")
#@gui :14.Method B=choice(0,"Subtraction","Addition","Multiplication")
#@gui :15.Link Start Numbers?=bool(0)
#@gui :_=separator(),_=note("<b>Palette</b>")
#@gui :16.Mode=choice(1,"Singular","Dual")
#@gui :17.Set=choice(0,"Foreground","Background")
#@gui :18.19.20.Color 1=color(255,255,255)
#@gui :21.22.23.Color 2=color(255,255,255)
#@gui :24.25.26.Color 3=color(255,255,255)
#@gui :27.28.29.Color 4=color(255,255,255)
#@gui :30.31.32.Color 5=color(255,255,255)
#@gui :33.34.35.Color 6=color(255,255,255)
#@gui :36.37.38.Color 7=color(255,255,255)
#@gui :39.40.41.Color 1=color(255,255,255)
#@gui :42.43.44.Color 2=color(255,255,255)
#@gui :45.46.47.Color 3=color(255,255,255)
#@gui :48.49.50.Color 4=color(255,255,255)
#@gui :51.52.53.Color 5=color(255,255,255)
#@gui :54.55.56.Color 6=color(255,255,255)
#@gui :57.58.59.Color 7=color(255,255,255)
#@gui :60.61.62.Color 1=color(255,255,255)
#@gui :63.64.65.Color 2=color(255,255,255)
#@gui :66.67.68.Color 3=color(255,255,255)
#@gui :69.70.71.Color 4=color(255,255,255)
#@gui :72.73.74.Color 5=color(255,255,255)
#@gui :75.76.77.Color 6=color(255,255,255)
#@gui :78.79.80.Color 7=color(255,255,255)
#@gui :_=separator(),_=note("<b>Shape</b>")
#@gui :81.Use Shape=bool(1)
#@gui :82.Tiled Shape=choice(3,"By Layer","Australia","Barbedwire","Circle","Crosshair","Cupid","Diamond","Dragon Curve-[D]","Dragonfly","Fern-[D]","Flip","Gear-[D]","Gumleaf","Heart","Information","Kookaburra","Mail","Mapleleaf","Paint Splat","Paw","Phone","Polygon-[D]","Rooster","Shopping Cart","Snowflake-[D]","Star-[D]")
#@gui :83.Fit Tile?=bool(1)
#@gui :84.Dragon Curve Recursion=int(10,0,30)
#@gui :85.Dragon Curve Rotation=float(0,-180,180)
#@gui :86.Fern Type=choice("Asplenium Adiantum-Nigrum","Thelypteridaceae")
#@gui :87.Fern Density (%)=float(100,0,300)
#@gui :88.Gear Teeth Count=int(8,3,32)
#@gui :89.Gear Height (%)=float(25,0.1,100)
#@gui :90.Gear Offset Teeth (%)=float(0,0,100)
#@gui :91.Gear Inner Ratio (%)=float(50,0.1,100)
#@gui :92.Polygon Vertices=int(5,3,100)
#@gui :93.Snowflake Recursion=int(5,1,6)
#@gui :94.Star Branches=int(3,5,100)
#@gui :95.Star Thickness (%)=float(38,.1,100)
#@gui :_=separator(),_=note("<b>Misc</b>")
#@gui :96.Position=choice(0,"10","100","1000","10000","100000")
#@gui :97.Position A=choice(0,"10","100","1000","10000","100000")
#@gui :98.Position B=choice(0,"10","100","1000","10000","100000")
#@gui :99.Push into Start Number=button()
#@gui :100.Push into Start A=button()
#@gui :101.Push into Start B=button()
#@gui :102.Push into Both=button()

I updated the script for extraction of unique u string. It returns them in order now:

Extract unique u string
import pyperclip as pc
import re
import numpy

gmic_str_paste=pc.paste()
gmic_str=str(gmic_str_paste)
lines=gmic_str.splitlines()

list_of_strings=[]

between_these_char="\_\"{(.*?)\}"

for l in lines:
    current_string=l.split('"')
    try:
        substring = re.search(between_these_char, l).group(1)
    except AttributeError:
        substring = re.search(between_these_char, l)
    if substring is None:
        continue
    else:
        list_of_strings.append("{"+substring+"}")

unique_list=numpy.unique(list_of_strings)
size_of_unique_list=int(len(unique_list))
order_unique_number=[]

for a in unique_list:
    n=0
    for line in list_of_strings:
        if line==a:
            order_unique_number.append(n)
            break
        n += 1

ordered_unique_list=[None] * len(unique_list)
order_unique_number.sort()

for n in range(0,len(unique_list)):
    ordered_unique_list[n]=list_of_strings[order_unique_number[n]]

for v in range(0,len(unique_list)):
    print("condition_"+str(v)+"="+str(ordered_unique_list[v]))

Thanks to @Ofnuts , and a few people at the python discord, a newer version of one of the existing script here is now here. As usual, to run it, copy your G’MIC codes based on the scope this script is meant to target, then execute the python script. This is meant for shifting numbers next to $ within the G’MIC language:

Code to shift numbers next to '$'
from functools import partial
import re
import pyperclip as pc

#test_string="test_var=$1 sharpen {5-2} variable_a=$7 variable_a=$18 variable_b,variable_8=${19-20} variable_d=$21 blur 10 ${10=}"

gmic_str_paste=pc.paste()
gmic_str=str(gmic_str_paste)

pattern = re.compile(r"(?<=\$)(?:\{(\d+)-(\d+)\}|(\d+)|\{(\d+)=\})")

def addfunc(m, *, n, v):
    def incif(num):
        return num + n if num >= v else num

    a, b, c , d = m[1], m[2], m[3], m[4]
    if a and b:
        a = incif(int(a))
        b = incif(int(b))
        return f'{{{a}-{b}}}'
    elif c:
        c = incif(int(c))
        return f'{c}'
    elif d:
        d = incif(int(d))
        return f'{{{d}=}}'

inc_number=input("Increment Number: ")
greater_or_equal_to_num=input("Affect only number greater or equal to: ")

add = partial(addfunc, n=int(inc_number), v=int(greater_or_equal_to_num))

out_string = pattern.sub(add, gmic_str)

#out_string  = pattern.sub(add, test_string)
#print(test_string)

print("\n"+out_string)

I should start a github repository for this.

EDIT: I added support for hexadecimal number for color(). This is mostly completed as it will work on the vast majority of cases now.

I think there may be issues with string that may be detected by regex inside note(""), but I don’t know if that can be addressed. I know it can, but not sure how to. I have not tested that part yet.

New version of `Number the GUI argument`
import pyperclip as pc
import re

pos=1
u_string=""

while True:
    init_mode=input("""
    Type in the one of the two characters in the set of two character at the left to use one of those mode?
    0F. Remove Number and Period. 
    1T. Add Numbers and Period 
    Choice: """)
    if init_mode=="0" or init_mode=="F":
        mode=False
        break
    elif init_mode=="1" or init_mode=="T":
        mode=True
        break

def output_number_dots(n):
    global pos
    global u_string
    out_str=""
    new_u_string=[]
    for p in range(n):
        out_str=out_str+str(pos+p)+"."
        new_u_string.append("$"+str(pos+p))
    new_u_string=",".join(new_u_string)
    u_string+="\"{"+new_u_string+"}\"\\\n"
    pos+=n
    return out_str
def count_number_color(inp_str):
    if inp_str[1]=='#':
        if len(inp_str)==9:
            return 3
        else:
            return 4
    else:
        return inp_str.count(",")+1
def process_level_2_mode_0(inp_str):
    current_pos=0
    for c in inp_str:
        if not (c.isnumeric() or c=='.'):
            break
        current_pos+=1
    return inp_str[current_pos:]
def process_level_2_mode_1(inp_str):
    try:
        variable_equal_type_str=re.search(level_2,inp_str).groups()
    except AttributeError:
        variable_equal_type_str=re.search(level_2, inp_str)
    if variable_equal_type_str is None:
        return inp_str
    separated_info=list(variable_equal_type_str)
    if separated_info[1]=="color":
        num_of_cols=count_number_color(separated_info[2])
        new_variable_name=output_number_dots(num_of_cols)+separated_info[0]
        separated_info[0]=new_variable_name
        separated_info[1]="="+separated_info[1]
    elif separated_info[1]=="point":
        separated_info[0]=output_number_dots(2)+separated_info[0]
        separated_info[1] = "=" + separated_info[1]
    else:
        separated_info[0]=output_number_dots(1)+separated_info[0]
        separated_info[1] = "=" + separated_info[1]
    return "".join(separated_info)

copied_code=pc.paste()
copied_code_str=str(copied_code)
copied_code_str_line=copied_code_str.splitlines()

level_0=r'(\#@gui\ :|\)\,(?=([A-Z]|[0-9])))(.*)=(int|float|choice|text|bool|button|point|color)(\(.*\)|{.*})(.*)'
level_1=r'((?<=\)),(?=[A-Z])|(?<=\}),(?=[A-Z])|(?<=\)),(?=[0-9])|(?<=\}),(?=[0-9]))'
level_2=r'(.*)=(int|float|point|choice|text|bool|color|button)(\(.*\)|{.*})(.*)'

print("\n")

for line in copied_code_str_line:
    search_result=re.search(level_0, line)
    if search_result==None:
        print(line)
    else:
        new_line=line[7:]
        level_1_search_result=re.search(level_1,new_line)
        if level_1_search_result==None:
            if mode==1:
                print("#@gui :"+process_level_2_mode_1(new_line))
            else:
                print("#@gui :" + process_level_2_mode_0(new_line))
        else:
            v_level_2=re.split(level_1,new_line)
            new_level_2=[]
            for index in v_level_2:
                if mode==1:
                    new_level_2.append(process_level_2_mode_1(index))
                else:
                    new_level_2.append(process_level_2_mode_0(index))
            print("#@gui :"+"".join(new_level_2))

if mode==1:
    print("\nu "+u_string)

It works for this case:

#@gui Sample Code: fx_rep_sample
#@gui :Integer Value=int(0,0,5)
#@gui :Float value=float(0,0,5)
#@gui :Choices=choice{0,"First Choice","Second Choice"}
#@gui :Point Location=point(50,50)
#@gui :Press this Button=button()
#@gui :Text Input=text("Here's a text")
#@gui :Checkmark=bool(0)
#@gui :Color A=color(0,50,20)
#@gui :Color B=color(210,55,180,220)
#@gui :_=note("Separated"),Variable After Comma=choice(0,"A","B")
#@gui :_=separator(),Preview Type=choice("Full","Forward Horizontal","Forward Vertical","Backward Horizontal","Backward Vertical","Duplicate Top","Duplicate Left","Duplicate Bottom","Duplicate Right","Duplicate Horizontal","Duplicate Vertical","Checkered","Checkered Inverse"),Preview Split=point(50,50,0,0,200,200,200,0,10)_0

Copying the string above and running the code, then using Mode 1 yields:

#@gui Sample Code: fx_rep_sample
#@gui :1.Integer Value=int(0,0,5)
#@gui :2.Float value=float(0,0,5)
#@gui :3.Choices=choice{0,"First Choice","Second Choice"}
#@gui :4.5.Point Location=point(50,50)
#@gui :6.Press this Button=button()
#@gui :7.Text Input=text("Here's a text")
#@gui :8.Checkmark=bool(0)
#@gui :9.10.11.Color A=color(0,50,20)
#@gui :12.13.14.15.Color B=color(210,55,180,220)
#@gui :_=note("Separated"),16.Variable After Comma=choice(0,"A","B")
#@gui :_=separator(),17.Preview Type=choice("Full","Forward Horizontal","Forward Vertical","Backward Horizontal","Backward Vertical","Duplicate Top","Duplicate Left","Duplicate Bottom","Duplicate Right","Duplicate Horizontal","Duplicate Vertical","Checkered","Checkered Inverse"),18.19.Preview Split=point(50,50,0,0,200,200,200,0,10)_0

u "{$1}"\
"{$2}"\
"{$3}"\
"{$4,$5}"\
"{$6}"\
"{$7}"\
"{$8}"\
"{$9,$10,$11}"\
"{$12,$13,$14,$15}"\
"{$16}"\
"{$17}"\
"{$18,$19}"\

New version of the ‘Number the GUI argument’ is finalized.

Changes:

  1. File/Folder are now allowed
  2. #@gui: can be space agnostic now. This is for G’MIC 3.1.5 and higher.

As usual, copy the #@gui header for filters, and then run this script.

New version of the 'Number the GUI argument'
import pyperclip as pc
import re

pos=1
u_string=""

while True:
    init_mode=input("""
    Type in the one of the two characters in the set of two character at the left to use one of those mode?
    0F. Remove Number and Period. 
    1T. Add Numbers and Period 
    Choice: """)
    if init_mode=="0" or init_mode=="F":
        mode=False
        break
    elif init_mode=="1" or init_mode=="T":
        mode=True
        break

def output_number_dots(n):
    global pos
    global u_string
    out_str=""
    new_u_string=[]
    for p in range(n):
        out_str=out_str+str(pos+p)+"."
        new_u_string.append("$"+str(pos+p))
    new_u_string=",".join(new_u_string)
    u_string+="\"{"+new_u_string+"}\"\\\n"
    pos+=n
    return out_str
def count_number_color(inp_str):
    if inp_str[1]=='#':
        if len(inp_str)==9:
            return 3
        else:
            return 4
    else:
        return inp_str.count(",")+1
def process_level_2_mode_0(inp_str):
    current_pos=0
    for c in inp_str:
        if not (c.isnumeric() or c=='.'):
            break
        current_pos+=1
    return inp_str[current_pos:]
def process_level_2_mode_1(inp_str):
    try:
        variable_equal_type_str=re.search(level_2,inp_str).groups()
    except AttributeError:
        variable_equal_type_str=re.search(level_2, inp_str)
    if variable_equal_type_str is None:
        return inp_str
    separated_info=list(variable_equal_type_str)
    if separated_info[1]=="color":
        num_of_cols=count_number_color(separated_info[2])
        new_variable_name=output_number_dots(num_of_cols)+separated_info[0]
        separated_info[0]=new_variable_name
        separated_info[1]="="+separated_info[1]
    elif separated_info[1]=="point":
        separated_info[0]=output_number_dots(2)+separated_info[0]
        separated_info[1] = "=" + separated_info[1]
    else:
        separated_info[0]=output_number_dots(1)+separated_info[0]
        separated_info[1] = "=" + separated_info[1]
    return "".join(separated_info)

copied_code=pc.paste()
copied_code_str=str(copied_code)
copied_code_str_line=copied_code_str.splitlines()

level_0=r'(\#@gui\s*:|\)\,(?=([A-Z]|[0-9])))(.*)=(int|float|choice|text|bool|button|point|color|folder|file)(\(.*\)|{.*})(.*)'
level_1=r'((?<=\)),(?=[A-Z])|(?<=\}),(?=[A-Z])|(?<=\)),(?=[0-9])|(?<=\}),(?=[0-9]))'
level_2=r'(.*)=(int|float|point|choice|text|bool|color|button|folder|file)(\(.*\)|{.*})(.*)'

print("\n")

for line in copied_code_str_line:
    search_result=re.search(level_0, line)
    if search_result==None:
        print(line)
    else:
        if line[:7]=="#@gui :":
            new_line=line[7:]
        else:
            new_line=line[6:]
        level_1_search_result=re.search(level_1,new_line)
        if level_1_search_result==None:
            if mode==1:
                print("#@gui:"+process_level_2_mode_1(new_line))
            else:
                print("#@gui:" + process_level_2_mode_0(new_line))
        else:
            v_level_2=re.split(level_1,new_line)
            new_level_2=[]
            for index in v_level_2:
                if mode==1:
                    new_level_2.append(process_level_2_mode_1(index))
                else:
                    new_level_2.append(process_level_2_mode_0(index))
            print("#@gui:"+"".join(new_level_2))

if mode==1:
    print("\nu "+u_string)

I’m thinking of converting these into a G’MIC script which creates a Python file, and these get executed directly.

Here are two problems:

How can I write #@gui code into a image representation of characters via G’MIC?
How can I do the same with a filter code?

Okay, I figured out how to make these python files accessible via G’MIC.

Download the current .py scripts I am using. And extract them into wherever you like-
GMIC-PY.zip (1.8 KB)

Copy and paste this code into user.gmic. Modify script_file_info into the location you extracted the files on.

#@cli run_pyscript:
#@cli : Run user-defined script. If you provide no argument, then it will print description on how to use your script. If you ran into a error, run without an argument, and modify your argument to make this work.
run_pyscript:
    skip "${1=}"
    
    _available_variables=""
    _number_of_available_scripts=0
    script_file_info="D:\\Documents\\Python\\"

    _$0_info modify_gui_vars,GUI-variable-inputs.py,"Modify GUI Variables to append numbers or to remove numbers into GUI Variables."
    _$0_info shift_vars_num,GMIC-Increment-Arg-Number.py,"Shift variables numbers."
    
    if narg($1)
        if isint($1)
         id=${arg\ $1+1,$_available_variables}
        else
         id=$1
        fi
        
        test_input=${_script_${id}_filename}
        if !narg($test_input) error invalid_arg fi
        script_file_info.=$test_input   
        
        e[0] "Executing script "${_script_${id}_filename}!\n
        exec 1,"python "$script_file_info
        e[0] "Finished executing script "${_script_${id}_filename}!
    else
        e[0] "Allowed arguments: 0-"{$_number_of_available_scripts-1}"(inclusive) or "$_available_variables.
        repeat $_number_of_available_scripts {
         current_variable=${arg\ $>+1,$_available_variables}
         e[0] Arg\ $>\ :\ $current_variable\ -\ ${_script_${>}_helper}
        }
    fi
    
    e[0] "End G'MIC interpreter."
    quit
_run_pyscript_info:
    check "$#==3"

    if narg($_available_variables)
     _available_variables.=,$1
    else
     _available_variables.=$1
    fi
    
    _script_$1_filename="$2"
    _script_$1_helper="$3"
    
    _number_of_available_scripts+=1

Execute the script in CLI like this:

$ run_pyscript 0

If everything is done correctly, it should look like this:

λ gmic run_pyscript 0
[gmic]./ Start G'MIC interpreter (v.3.3.2).
[gmic]./ Executing script GUI-variable-inputs.py!

    Type in the one of the two characters in the set of two character at the left to use one of those mode?
    0F. Remove Number and Period.
    1T. Add Numbers and Period
    Choice: 1


#@gui Satellite: fx_rep_satellite,fx_rep_satellite_preview
#@gui:_=separator(),_=note("<b>Main</b>")
#@gui:1.Color Mapping Methodology=choice(5,"Custom","Aviation","Dvorak","Funktop","JSL2","IR2","IR2-Fire","IR2-Summer","IR2-Cool Winter","Rainbow","Rainbow Top","IR3-Water Vapor","IR3-Blue")
#@gui:2.Color To Gray Mode=choice(0,"Rec-709","NTSC","ITU-R.BT.601","Lightness","Minimum","Maximum","Average")
#@gui:3.Midpoint Position(%)=float(0,-100,100)
#@gui:4.Sigmoid Level(%)=float(0,0,100)
#@gui:5.Normalize=bool(0)
#@gui:_=separator(),_=note("<b>Custom Palette</b>")
#@gui:6.Number of Gradient Bands=int(2,2,60)
#@gui:7.Create Banded Gradient from Minimal Colors=button()
#@gui:8.Create Banded Gradient from Maximal Colors=button()
#@gui:9.Create Banded Gradient from Current Palette=button()

u "{$1}"\
"{$2}"\
"{$3}"\
"{$4}"\
"{$5}"\
"{$6}"\
"{$7}"\
"{$8}"\
"{$9}"\


[gmic]./ Finished executing script GUI-variable-inputs.py!
[gmic]./ End G'MIC interpreter.

NOTE: If you changed file name or whatever, you need to change the code to reflect that.

Now, I have updated a repository for this purpose. And then, there’s instruction there too.