Reptorian G'MIC Filters

I’ll give a update and thoughts by new year. Other than that, I will eventually depreciate two commands with 1 command.

--rep_num2base_float_max
--rep_num2altbase
++rep_posdec2base_img

Simply put, this address both of them at once. The new command can be used to convert any large number into an arbitrary base representation as a image as well as number smaller than 1<<53 into an arbitrary base representation. Maybe I should do something about supporting negative number, but I really doubt that you’re going to need that.

Here’s a preview of the new command:

C:\Windows\System32>gmic tic +new_rep_posdec2base_img 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719,bin toc
[gmic]./ Start G'MIC interpreter (v.3.3.3).
[gmic]./ Initialize timer.
[gmic]./ Elapsed time: 0.03 s.
[gmic]./ Display image [0] = 'base); remainder; ]'.
[0] = '[<begin( const base=$base; n=$n; ); remainder=n%base; n=int(n...':
  size = (1804,1,1,1) [7216 b of float32].
  data = (1,1,0,1,0,1,1,1,0,0,1,1,0,0,0,0,1,1,0,1,1,0,1,0,1,1,0,1,0,0,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ... ,1,0,0,0,1,1,1,1,0,0,1,0,1,0,0,0,0,0,1,1,0,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1).
  min = 0, max = 1, mean = 0.27051, std = 0.444346, coords_min = (2,0,0,0), coords_max = (0,0,0,0).
[gmic]./ End G'MIC interpreter.

Here is what the help document says:

C:\Windows\System32>gmic h rep_posdec2base_img

  rep_posdec2base_img:
      'decimal_number',base

    Output numberical representation of a decimal number in given base as a
    image. Each pixels are digit representation of a number. This can also be
    used to represent really huge decimal number. 1000+ digits decimal number
    is supported.

    'base' can be a integer number between 2 to 16777216 (Inclusive for both).
    In addition, you can use the following string as argument for 'base': bin,
    oct,dec,base_float.

Looks like I managed to have G’MIC convert a binary of 90000 digits to decimal format in ~7.5 s. :smiley:

Yes, that is slow, but acceptable given that there’s almost no use case for this in G’MIC.

C:\Windows\System32>gmic ('1${rep_random_binary\ 90000}') -. {_'0'} tic rep_binimg2decimg toc +. {_'0'} echo {t} rm.
[gmic]./ Start G'MIC interpreter (v.3.3.3). (1 image 90001x1x1x1).
[gmic]./ Subtract 48 to image [0].
[gmic]./ Initialize timer.
[gmic]./ Elapsed time: 7.359 s.
[gmic]./ Add 48 to image [0].
903379934146847249562266501943898308931906808178153245648311576533795631129440017149497778696965686062818231247944573664878625084968306383800881418521856308739006835402996185692655407714427598179955463025385413903277853082598384436866831056707391627521878131664107737593291485275377729355653102457847786815577201048513265693293508747967291076288560480045187904338253755432702534256958020118120196417974957430576404388931004079908172181571314141656979073118558992412412158267864802296318079339643895760835719412110024355754............

And of course, the proof that it works:

C:\Windows\System32>gmic ('1${rep_random_binary\ 512}') echo {t} -. {_'0'} tic rep_binimg2decimg toc +. {_'0'} echo {t} rm.
[gmic]./ Start G'MIC interpreter (v.3.3.3). (1 image 513x1x1x1).
100111101101001011010100101111010010101001100001011000100111000100001100111110001100111100010110111010101100111011101110001111000110010011111011101100001110100110100100000011111100001000101011111101011101111011100101110001000001101100010110011100001110000110111010011101001100111100100100010111000100010010100101101000000100111001100110001010110111110100111101110000111101110001101001111110000101010100110101101011000000111000001001111010110011101010110011110110110110010001111001101111001111010001111111010000011
[gmic]./ Subtract 48 to image [0].
[gmic]./ Initialize timer.
[gmic]./ Elapsed time: 0.001 s.
[gmic]./ Add 48 to image [0].
16636529445109365930563111588952357240380826039501819059572605835918031696598781256273907829880900585814893810803901427080226008196626797789957142463708803
[gmic]./ Remove image [0] (0 images left).
[gmic]./ End G'MIC interpreter.

C:\Windows\System32>python
Python 3.10.6 (tags/v3.10.6:9c7b4bd, Aug  1 2022, 21:53:49) [MSC v.1932 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 0b100111101101001011010100101111010010101001100001011000100111000100001100111110001100111100010110111010101100111011101110001111000110010011111011101100001110100110100100000011111100001000101011111101011101111011100101110001000001101100010110011100001110000110111010011101001100111100100100010111000100010010100101101000000100111001100110001010110111110100111101110000111101110001101001111110000101010100110101101011000000111000001001111010110011101010110011110110110110010001111001101111001111010001111111010000011
16636529445109365930563111588952357240380826039501819059572605835918031696598781256273907829880900585814893810803901427080226008196626797789957142463708803
>>> exit()
2 Likes

I forgot to write my 2023 in review, but here it is. I been spending some times to focus on other things, and there haven’t been much new filters.

My main goal for 2023 was to refactor as much as I can, and to improve upon my own filters. I must admit, I failed with completing that goal for G’MIC and that have not changed, but I think with the complexity of my filters and the number of lines of codes involved, I don’t think that was ever a realistic goal.

So, the goal remains unchanged, and I still will mostly work on refactoring. There’s some few new commands here and there. Some of my string processing commands which are new are also related to refactoring. I know that might seems strange, but to clarify, look at the Lyapunov Fractal filters, it is apparent that ABC string permutations there. There is also work being done on making color palette choice GUI development easier.

5 Likes

- Tiny update to the refactor work (not really interesting for now) -

On Mitchell Concatenation, there’s these commands I have made:

rep_element_wise_addition
rep_element_wise_multiply

And I implemented the Schönhage–Strassen algorithm into my new version of element wise multiplication. Old one use US grade-school math algorithm.

C:\Windows\System32>gmic +rep_mitchell_concatenation_base 1000,1000,250,{(250*250*250-500)} tic new_rep_element_wise_multiply 0,1,250 toc
[gmic]./ Start G'MIC interpreter (v.3.3.3).
[gmic]./ Initialize timer.
[gmic]./ Elapsed time: 0.142 s.
[gmic]./ Display image [0] = '[unnamed]'.
[0] = '[unnamed]':
  size = (1000,1000,1,1) [3906.3 Kio of float32].
  data = (177,29,204,179,108,18,74,44,164,10,69,163,97,5,193,35,159,4,196,161,102,7,82,40,178,13,101,173,139,23,7,59,237,36,50,199,224,52,234,93,102,73,59,240,123,97,29,141,39,124,145,45,102,155,158,203,64,190,72,114,177,228,138,29, ... ,142,145,128,111,92,54,15,225,167,109,48,221,144,64,219,124,26,164,51,187,58,180,49,156,12,116,209,51,141,221,50,127,195,12,77,133,189,244,40,86,130,167,204,240,19,48,75,97,119,139,155,171,185,196,207,216,223,230,235,239,243,245,248,0).
  min = 0, max = 249, mean = 124.532, std = 72.1205, coords_min = (157,0,0,0), coords_max = (149,0,0,0).

C:\Windows\System32>gmic +rep_mitchell_concatenation_base 1000,1000,250,{(250*250*250-500)} tic rep_element_wise_multiply 0,1,250 toc
[gmic]./ Start G'MIC interpreter (v.3.3.3).
[gmic]./ Initialize timer.
[gmic]./ Elapsed time: 15.256 s.
[gmic]./ Display image [0] = '[-1]'.
[0] = '[-1]':
  size = (1000,1000,1,1) [3906.3 Kio of float32].
  data = (177,29,204,179,108,18,74,44,164,10,69,163,97,5,193,35,159,4,196,161,102,7,82,40,178,13,101,173,139,23,7,59,237,36,50,199,224,52,234,93,102,73,59,240,123,97,29,141,39,124,145,45,102,155,158,203,64,190,72,114,177,228,138,29, ... ,142,145,128,111,92,54,15,225,167,109,48,221,144,64,219,124,26,164,51,187,58,180,49,156,12,116,209,51,141,221,50,127,195,12,77,133,189,244,40,86,130,167,204,240,19,48,75,97,119,139,155,171,185,196,207,216,223,230,235,239,243,245,248,0).
  min = 0, max = 249, mean = 124.532, std = 72.1205, coords_min = (157,0,0,0), coords_max = (149,0,0,0).
[gmic]./ End G'MIC interpreter.

So, essentially my recent version of element_wise_multiplication is 107x faster. Most of the speedup comes from using negative opacity value within copy() which allows me to do multiplication and adding into array at once.

EDIT: I made a small mistake, and fixed it, and now I have time of .086 s and .078 s. 177x to 195x speedup!

And I think this can be used to speed up binary to decimal conversion too!

Finally, saw a issue with the algorithm though, it doesn’t seem to work with 4 or more multipliers that well. Well, it is what it is, and written a error clause when 4 or more multipliers is used. It’s correct for every other cases though as you can see here:

C:\WINDOWS\system32>gmic 5,1,1,3,1 rep_element_wise_multiply 1,1,2
[gmic]./ Start G'MIC interpreter (v.3.3.3).
[gmic]./ Input image at position 0, with values '1' (1 image 5x1x1x3).
[gmic]./ Display image [0] = '[unnamed]'.
[0] = '[unnamed]':
  size = (15,1,1,1) [60 b of float32].
  data = (1,1,1,0,1,0,0,0,1,0,1,1,1,1,1).
  min = 0, max = 1, mean = 0.666667, std = 0.48795, coords_min = (3,0,0,0), coords_max = (0,0,0,0).
[gmic]./ End G'MIC interpreter.

C:\WINDOWS\system32>python
Python 3.10.6 (tags/v3.10.6:9c7b4bd, Aug  1 2022, 21:53:49) [MSC v.1932 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> bin(0b11111**3)
'0b111010001011111'
>>> exit()

And the stat observation for the speed test result.

Update to the binary to decimal conversion tool I made, with Schönhage–Strassen algorithm and using base 10M, I was able to shorten the time to convert binary to decimal representation from 7.5 s to 1.345 s for a 90000 digit binary number.

You can see my results here.

C:\Windows\System32>gmic ('1000101010101010101011111111011110000000011111101010010100101111111110000000011111111111000111') -. {'0'} new_rep_binimg2decimg echo {crop(#-2)}

1,728819,9311048,5358681,3779911,4,0,0,0,5

Ignore the extra numbers 4,0,0,0,5 because these came from the fact I’m using dynamic array code.

1, 728819,9311048,5358681,3779911
1 0728819 9311048 5358681 3779911

Bottom is Python result, top is G’MIC result. That’s basically why I want a update to v2s() in math parser.

And the code for you people to analyze:

#@cli new_rep_binimg2decimg:
#@cli : Convert image(s) representing a binary number as a image representing the decimal representation of the binary number within image(s).
new_rep_binimg2decimg:

foreach {
    if im<0||iM>1 error no_binary_image fi
    
    crop {xM},100%
    
    name binary_image
    
    if w>53
    
        {ceil(w/24)},1,1,1,"begin(
                const max_x = w#-1-1;
                const bits = 24;
            );
            start_point = max_x-(x*bits);
            end_block = max(-1,start_point-bits);
            bitshift_factor = 0;
            output_value = 0;
            for(ind = start_point, ind>end_block, --ind,
                output_value |= i[#-1,ind] << bitshift_factor;
                bitshift_factor++;
            );
            output_value;" => base_float_ref_img
        
        remove[binary_image]
        
        bool_v10M={i[#-1,0]>=1e7}
        1,1,1,{2+$bool_v10M},v=i[#-1,0];$bool_v10M?[1,v%1e7,2]:[v,1]; permute. xcyz => bin2dec_result_img
        crop[base_float_ref_img] 1,100%
        (1;6777216;2) => mult_ref
        
        eval[base_float_ref_img] >"
            begin(
                const base_10M = 1e7;
                const multiplier_reference = $mult_ref;
                const bin2dec_result_img = $bin2dec_result_img;
                const second_digit = 6777216;
                const mx = w-1;
            );
            if(i,
                current_second_digit = i%base_10M;
                use_first_digit = i>=base_10M;
                result_remainder = remainder = old_value = t_old_value = 0;
                repeat_factor = da_size(#multiplier_reference);
                result_digit_pos = da_size(#bin2dec_result_img)-1;
                while( repeat_factor--,
                    t_old_value = i[#multiplier_reference, repeat_factor];
                    reference_value =  t_old_value*current_second_digit+old_value+remainder; 
                    target_value = ( reference_value % base_10M ) + result_remainder + i[#bin2dec_result_img,result_digit_pos] ;
                    if(result_digit_pos>-1
                    ,i[#bin2dec_result_img,result_digit_pos--] = target_value % base_10M ;
                    ,da_insert(#bin2dec_result_img,0,target_value % base_10M);
                    );
                    if(use_first_digit , old_value = t_old_value );
                    result_remainder = int ( target_value / base_10M );
                    remainder        = int ( reference_value / base_10M ) ;
                );
                result_remainder+=remainder;
                if(use_first_digit, result_remainder+= old_value);
                while(result_remainder,
                    da_insert(#bin2dec_result_img,0, (result_remainder ) % base_10M );
                    result_remainder = int ( result_remainder / base_10M );
                );
            );
            if(x<mx,
                remainder=old_value=0;
                repeat_factor = da_size(#multiplier_reference);
                while( repeat_factor--,
                    t_old_value = i[#multiplier_reference,repeat_factor];
                    result = t_old_value*second_digit+old_value+remainder;
                    i[#multiplier_reference,repeat_factor] = result % base_10M;
                    remainder = int( result / base_10M );
                    old_value = t_old_value;                
                );
                remainder+=old_value;
                while( remainder,
                    da_insert(#multiplier_reference,0,remainder%base_10M);
                    remainder = int ( remainder / base_10M );
                );
            );
            "
        
    else
        eval[-1] <begin(m=0;n=0;);n|=i<<m;++m;end(set('\{\}',v2s(n));); rm.
        ('${}') -. {_'0'}
    fi
}

Bad news: Never mind.

After a while, I have managed to update the binary number to decimal number related tools, and managed to have it zippy as possible with the criterias I want (as big as possible) with a new algorithm I made (it has not been made by any one else). Converting a 90001 digit binary to its decimal representation takes 1-1.2 s after some more tests. You could test the speed with a 300x300 binary image using Tupper’s Self Referential Formula via GUI plugin, and you’d get the output quickly. It’s not instantaneous though.

From memory, here are the times to convert binary with specified number of digits to decimals:

90001 - 1.15 s
160001 - 5.5 s
262001 - 10.5 s

I do have to wonder what’s the time complexity of the algorithm I invented though. It’s not O(n), but it’s not O(n^2) either given it works in chunks.


I have a question now, should the default on second parameter be 1 or true? @afre @garagecoder and @grosgood . It seems like it can go either way I think.

#@cli rep_random_binary: num_of_chars>0, _start_with_1={ 0=false | 1=true }
#@cli : Return randomly generated binary number based on number of characters.
#@cli :
#@cli : Author : Reptorian.
rep_random_binary:
skip ${2=1}
check "$1&&isint($1)"
s0:=($1>1)&&$2

if $s0 u {`[_'1',expr('int(u(_'0',_'2',1,0))',$1-1)]`}
else   u {`[expr('int(u(_'0',_'2',1,0))',$1)]`}
fi

Also, I think this can be extended as well now to come to think of it.

1 Like

‘1’ or ‘0’, rather than ‘True’ or ‘False’, because furnishing patterns of digits of specific width is the service that the command provides. If, instead, the service is about furnishing patterns of the words ‘True’ or ‘False’, then specifying ‘True’ or ‘False’ for the second parameter is more consistent. This suggestion is based entirely on presenting the user an argument behavior consistent with command behavior. Internally, as you point out, G’MIC couldn’t care less.

However, if you permit me to go further, then why expose the argument choice at all? I avow for asking the user the minimum amount of information necessary to get under way with the job, to wit: providing the user with a random sequence of ‘1’ and ‘0’ glyphs of a specific width (maybe thousands). Since I am making use of your command to obtain a random sequence, then why the bureaucratic overhead of asking about un-random leftmost glyphs? You’ve already made it optional. Make it go away entirely; you’ll have a cleaner interface.

3 Likes

I agree. When making commands/filters, I keep things as simple and logical as possible for the user. That goes for the code as well. Best make it clean so that viewers can understand its purpose at a glance. For more abstract or complex code, add comments. Circling back to 1 or 0 vs True or False, I prefer the former for the same reason as Garry. If you want to elaborate, you could do so in the filter description section.

1 Like

Reptorian - I fixed 2 errors in your channel-overblur-overline filter.
line 111 local[0] not local[1] it no longer starts when set to 1.

Also for me color space for multiple layers only works on RGB/sRGB

I find it usable for the videos I make.
Like this one.

1 Like

Ok, feel free to make a pull request or share code here.

Never mind, I decided to refactor it and have just started on that.

Thanks Reptorian, I saw the error message in the console of the latest G’MIC and sure enough it was an easy fix. I only use this filter with RGB on multiple files so don need to change that. I found that using with ‘multiply’ on RGB really boosts any image to the point where it needs to be turned-down :slight_smile:

BTW Thanks for making these cool filters.

1 Like

Thank you. I rarely get my filters appreciated overtly. I know others out there are appreciating my work.


Here’s a CLI version of the filter @TasMania17 was talking about (as part of refactor):

#@cli rep_cbsoo: eq. to 'rep_channels_overblur_overline_blur_sharpen'.
rep_cbsoo: rep_channels_overblur_overline_blur_sharpen $*
#@cli rep_channels_overblur_overline_blur_sharpen: method_a={ 0=blur | 1=sharpen | 2=overblur | 3=overline },0%<_effect_factor_a[%]<=100%,_multiplication_factor>0,_blending_mode,0<_blending_opacity[%]<=100%...
#@cli : Apply OOBS filtering over channels within images.
#@cli : 'blending_mode' can be { add | alpha | and | average | burn | darken | difference | divide | dodge | exclusion | freeze | grainextract | grainmerge | hardlight | hardmix | interpolation | lighten | linearburn | linearlight | multiply | normal | negation | or | overlay | pinlight | reflect | screen | shapeaverage | softburn | softdodge | softlight | stamp | subtract | vividlight | xor' }.
#@cli : - Note on 3 Channels Color Spaces (RGB, HSV...) input -
#@cli : If you want to perform the same setting on all channel at once, simply use 5 arguments.
#@cli : If you want to perform same setting on all color channel at once, but separate for gray and alpha. Use 5*(contain_gray+contain_color+contain_alpha) arguments.
#@cli : If you want to perform separate setting on different channels. You can use '-' to disable individual channel, or empty space to skip color channels altogether.
#@cli : Author : Reptorian.
#@cli : Default values: '_effect_factor=100%','_multiplication_factor=100%','_blending_mode=21','_blending_opacity=100%','_effect_boundary=1'
#@cli : $ sp lena shape_cupid 512 blur. 10 *. 255 cut. 0,255 a c sp house rep_channels_blur_sharpen_overblur_overline 2,150,1.5,normal,100%,2,100,1,xor,100%,1,50,1,grainextract,100%
#@cli : $ sp lena shape_cupid 512 blur. 10 *. 255 cut. 0,255 a c sp house rep_channels_blur_sharpen_overblur_overline 2,150,1.5,normal,100%
#@cli : $ sp lena shape_cupid 512 blur. 10 *. 255 cut. 0,255 a c sp house rep_channels_blur_sharpen_overblur_overline 3,150,1.5,normal,100%,2,100,1,xor,20%,3,200,2,linearlight,100%,-,1,200,1,normal,100%
rep_channels_blur_sharpen_overblur_overline:
$=arg

_$0_list_of_blending_modes=_$0_add,_$0_alpha,_$0_and,_$0_average,_$0_burn,_$0_darken,_$0_difference,_$0_divide,_$0_dodge,_$0_exclusion,_$0_freeze,_$0_grainextract,_$0_grainmerge,_$0_hardlight,_$0_hardmix,_$0_interpolation,_$0_lighten,_$0_linearburn,_$0_linearlight,_$0_multiply,_$0_normal,_$0_negation,_$0_or,_$0_overlay,_$0_pinlight,_$0_reflect,_$0_screen,_$0_shapeaverage,_$0_softburn,_$0_softdodge,_$0_softlight,_$0_stamp,_$0_subtract,_$0_vividlight,_$0_xor
num_of_blending_modes={narg(${_$0_list_of_blending_modes})}
${_$0_list_of_blending_modes}={expr('x',$num_of_blending_modes)}
('${_$0_list_of_blending_modes}')
replace_str. _$0_,"" _$0_list_of_blending_modes={t} rm.

m $0_bsoo_edit:"
 pos,use_char={$""1>1?[$""1-1,1]:[$""1+1,0]}

 if $use_char char=+ fi

 $char${arg\\ $pos,blur,sharpen} $""2 

 if $""1>1
  +-[-2,-1] abs[-1]
  *[-1] $""3
  rm[-2]
  +[-2,-1]
 fi
 "
 
m +$0_bsoo_edit:"
 pos={$""1>1?$""1-1:$""1+1}
 +${arg\\ $pos,blur,sharpen} $""2
 
 if $""1>1
  +-[-2,-1] abs[-1]
  *[-1] $""3
  rm[-2]
  +[-1] [-2]
 fi
 "
 
m $0_process_individual_channel_section:"
  method,effect_factor,multiplication,opacity:=[$""{2-5}]
  use_output=0
  
  if $effect_factor||$opacity>0
   use_output=1
   
   input_blending=$""6
   if isnum($input_blending)
    if !isint($input_blending) error invalid_arg fi
    blending:=$input_blending%"$num_of_blending_modes"
   else
    blending=${_$0_$input_blending}
   fi
   blend_str=${arg\\ $blending+1,"${_$0_list_of_blending_modes}"}
   
   if ($blending==${_$0_normal})&&($opacity==1)
    m $0_process_$""1:$0_bsoo_edit\\ $method,$effect_factor,$multiplication\\ cut\\ 0,255
   else
    m $0_process_$""1:+$0_bsoo_edit\\ $method,$effect_factor,$multiplication\\ blend\\ $blend_str,$opacity
   fi
  fi

  status $use_output
 "

cmyk_mode,max_col_spec_size={m='$-1'=='cmyk';[m,3+(m?1)]}
user_cmyk_mode=$cmyk_mode

do

 eval "
  const num_of_imgs=$!;
  const cmyk_mode=$cmyk_mode;
  const max_col_spec_size=$max_col_spec_size;
  contain_gray=contain_alpha=0;
  continue_analyzing_color_space=0;
  cmyk_mode?(
   contain_rgb=contain_cmyk=0;
   repeat(num_of_imgs,p,
    if(!contain_gray?s#p<3,contain_gray=1;);
    if(!contain_cmy?s#p==3,contain_cmy=1;);
    if(!contain_cmyk?s#p>=4,contain_cmyk=1;);
    if(!contain_alpha?s#p==2||s#p>max_col_spec_size,contain_alpha=1;);
    if(contain_alpha&&contain_rgb&&contain_cmyk&&contain_alpha,break(););
   );
   set('contain_gray',contain_gray);
   set('contain_cmy',contain_cmy);
   set('contain_cmyk',contain_cmyk);
   set('contain_alpha',contain_alpha);
  ):(
   contain_color=0;
   repeat(num_of_imgs,p,
    if(!contain_gray?s#p<3,contain_gray=1;);
    if(!contain_color?s#p>2,
     contain_color=1;
     if(s#p>4,
      set('cmyk_mode',1);
      set('max_col_spec_size',4);
      continue_analyzing_color_space=1;
      break();
     );
    );
    if(!contain_alpha?s#p==2||s#p>max_col_spec_size,contain_alpha=1;);
   );
   if(!continue_analyzing_color_space,
    set('contain_gray',contain_gray);
    set('contain_color',contain_color);
    set('contain_alpha',contain_alpha);
   );
  );
  set('continue_analyzing_color_space',continue_analyzing_color_space);"

while $continue_analyzing_color_space

############################################
# Reference for code: Result of CMYK       #
# [gmic]./ g0,cmy0,cmyk1,alpha0 => 1,4     #
# [gmic]./ g0,cmy0,cmyk1,alpha1 => 2,5     #
# [gmic]./ g0,cmy1,cmyk0,alpha0 => 1,3     #
# [gmic]./ g0,cmy1,cmyk0,alpha1 => 2,4     #
# [gmic]./ g0,cmy1,cmyk1,alpha0 => 2,3,5,7 #
# [gmic]./ g0,cmy1,cmyk1,alpha1 => 3,5,6,8 #
# [gmic]./ g1,cmy0,cmyk0,alpha0 => 1,1     #
# [gmic]./ g1,cmy0,cmyk0,alpha1 => 2,2     #
# [gmic]./ g1,cmy0,cmyk1,alpha0 => 2,5     #
# [gmic]./ g1,cmy0,cmyk1,alpha1 => 3,6     #
# [gmic]./ g1,cmy1,cmyk0,alpha0 => 2,4     #
# [gmic]./ g1,cmy1,cmyk0,alpha1 => 3,5     #
# [gmic]./ g1,cmy1,cmyk1,alpha0 => 3,5,6,8 #
# [gmic]./ g1,cmy1,cmyk1,alpha1 => 4,6,7,9 #
############################################

#####################################
# Reference for code: Result of RGB #
# [gmic]./ g0,rgb1,alpha0 => 1,3    #
# [gmic]./ g0,rgb1,alpha1 => 2,4    #
# [gmic]./ g1,rgb0,alpha0 => 1,1    #
# [gmic]./ g1,rgb0,alpha1 => 2,2    #
# [gmic]./ g1,rgb1,alpha0 => 2,4    #
# [gmic]./ g1,rgb1,alpha1 => 3,5    #
#####################################

var_method,var_effect_factor,var_multiplication_factor,var_blending,var_opacity:=expr('x+1',5)

if $cmyk_mode error in_development
else
 
 num_of_contains,num_of_set_args,gray_start={[sum($contain_gray,$contain_color,$contain_alpha),ceil($#/5)]},$contain_gray
  
 if $num_of_set_args!=$num_of_contains||(($#-$num_of_set_args*5)>0)
  use_gray,use_color,use_alpha,\
  use_channel_0,use_channel_1,use_channel_2=0
  
  if $contain_gray 
   current_method=${arg$var_method}
   if narg($current_method)?'$current_method'!='-'
    use_gray=${$0_process_individual_channel_section\ gray,${arg$var_method},${arg$var_effect_factor},${arg$var_multiplication_factor},${arg$var_opacity},${arg$var_blending}}
    var_method,var_effect_factor,var_multiplication_factor,var_blending,var_opacity+=5
   else
    var_method,var_effect_factor,var_multiplication_factor,var_blending,var_opacity+=1
   fi
  fi
  
  if $contain_color
   current_method=${arg$var_method}
   if narg($current_method)
    repeat 3 {
     if '$current_method'=='-'
      var_method,var_effect_factor,var_multiplication_factor,var_blending,var_opacity+=1
     elif narg($current_method)
      use_channel_$>=${$0_process_individual_channel_section\ channel_$>,${arg$var_method},${arg$var_effect_factor},${arg$var_multiplication_factor},${arg$var_opacity},${arg$var_blending}}
      if !$use_color use_color=${use_channel_$>} fi
      var_method,var_effect_factor,var_multiplication_factor,var_blending,var_opacity+=5
     else error inval_arg
     fi
     current_method=${arg$var_method}
    }
   else
    var_method,var_effect_factor,var_multiplication_factor,var_blending,var_opacity+=1
   fi
  fi
  
  if $contain_alpha
   current_method=${arg$var_method}
   if narg($current_method)?'$current_method'!='-'
    use_alpha=${$0_process_individual_channel_section\ alpha,${arg$var_method},${arg$var_effect_factor},${arg$var_multiplication_factor},${arg$var_opacity},${arg$var_blending}}
   fi
  fi
  
  if !sum($use_gray,$use_color,$use_alpha) return fi
  
  foreach {
   contain_color,contain_alpha:=[s>2,!(s&1)]
   
   if $use_alpha?$contain_alpha 
    s c,-{s-1}
    if $use_alpha $0_process_alpha[-1] fi
   fi
   
   if $contain_color?$use_color
    s[0] c
    foreach[0-2] {
     if ${use_channel_$>}
      $0_process_channel_$>
     fi 
    }
   elif $use_gray $0_process_gray[0]
   fi
   
   a c
  }
 elif $num_of_set_args==1
  method,effect_factor,multiplication,opacity:=[${arg$var_method},${arg$var_effect_factor},${arg$var_multiplication_factor},${arg$var_opacity}]
  
  input_blending=${arg$var_blending}
  if isnum($input_blending)
   if !isint($input_blending) error invalid_arg fi
   blending:=$input_blending%$num_of_blending_modes
  else
   blending=${_$0_$input_blending}
  fi
  blend_str=${arg\ $blending+1,${_$0_list_of_blending_modes}}

  if !$effect_factor||$opacity<=0 return fi
  
  if ($blending==${_$0_normal})&&($opacity==1)
   foreach { $0_bsoo_edit $method,$effect_factor,$multiplication cut 0,255 }
  else
   foreach {
    +$0_bsoo_edit $method,$effect_factor,$multiplication 
    blend $blend_str,$opacity
   }
  fi
 elif !$num_of_set_args
  error needs_at_least_5_for_one_arg_set
 else
  if $contain_gray
    use_gray=${$0_process_individual_channel_section\ gray,${arg$var_method},${arg$var_effect_factor},${arg$var_multiplication_factor},${arg$var_opacity},${arg$var_blending}}
    var_method,var_effect_factor,var_multiplication_factor,var_blending,var_opacity+=5
  fi
  if $contain_color
    use_color=${$0_process_individual_channel_section\ color,${arg$var_method},${arg$var_effect_factor},${arg$var_multiplication_factor},${arg$var_opacity},${arg$var_blending}}
    var_method,var_effect_factor,var_multiplication_factor,var_blending,var_opacity+=5
  fi
  if $contain_alpha
    use_alpha=${$0_process_individual_channel_section\ alpha,${arg$var_method},${arg$var_effect_factor},${arg$var_multiplication_factor},${arg$var_opacity},${arg$var_blending}}
  fi
  
  if !sum($use_gray,$use_color,$use_alpha) return fi
  
  foreach {
   contain_color,contain_alpha:=[s>2,!(s&1)]
   
   if $use_alpha?$contain_alpha
    shared[-1] {s-1}
    $0_process_alpha[-1]
    rm.
   fi
   
   if $contain_color?$use_color
    if $contain_alpha shared[-1] 0,{s-2} fi
    $0_process_color[-1]
    if $contain_alpha rm[-1] fi
   elif $use_gray
    if $contain_alpha shared[-1] 0,{s-2} fi
    $0_process_gray[-1]
    if $contain_alpha rm[-1] fi
   fi
  }
 fi
 
fi

um $0_bsoo_edit,+$0_bsoo_edit,$0_process_gray,$0_process_color,$0_process_channel_0,$0_process_channel_1,$0_process_channel_1,$0_process_channel_2,$0_process_alpha

Probably a little too complicated, but it’ll make the GUI a lot easier after I’m finished with CMYK/A part (which haven’t been started).

A new G’MIC filter?

rep_thefoldster_img:
512,512,53,1,"begin(
  modpower(a,b,c)=(
   res=1;
   current_a=a;
   current_b=b;
   
   current_a%=c;
   if(!current_a,res=0;);
   current_a>0?(
    while(current_b,
     if((current_b&1),res=(res*current_a)%c;);
     current_b>>=1;
     current_a=sqr(current_a)%c;
    );
    res;
   );
  );
 );
 v=modpower(xor(abs(x+y),abs(x-y)+1),37,1<<(1+z));
 1==v%7;
 "
split z

With just v:

image

4 Likes

Guess I’ll put it in the backburner though it’s complete.

Here’s another idea:

image

So, the first image gives me a hint on how to do the openprocessing one via G’MIC. However, I’ll have a look at this later and just posted this to put it in the backburner. Anyway, I’m half-way done with reengineering OOBS filter, and I’m having over 500+ lines of code just to do the GUI elements control part, so no wonder this took me a while. I think it’ll reach 800+ lines of code just for that, and wow…

1 Like

The circular tree looks nice and fun.

Looks like OOBS alone is longer than my whole gmic file…

Now, it’s not that longer. Far shorter actually, but eventually the cli and gui combination will be over that.

Also, I reviewed your code a bit.

# Snip 1: {w/$1},{h/$1} 
# Snip 1 (Suggested): {[w,h]/$1}

# Snip 2: floor(u(2,50))
# Snip 2 (Suggested 2 if 50 is to be included): v(2,50)
# Snip 2 (Suggested otherwise): v(2,49)

Other than that, I think I get your code just from reading it.

Also, remove the @ found in here:

#@cli pr_da@b: image_1,image_2,...
#@cli : Create alpha-blended images using existing images and insert onto the last list. If no arguments are specified, all images are blended as a new layer.
pr_dab :
if $!>1
  if $#>1 +blend[$*] alpha
  else +blend alpha
  fi
fi
display

Though I think it would be a nice idea to use @ to allow to make library. It doesn’t work however:

foo@out: 
echo pass
1 Like

Now… where does that come from? Must have happened when i had my touchpad in “touch” mode. Pretty annoying. Anyway i never use this command… completely forgot about it, haha!
Fixed it in git, will do the rest in my local file before uploading later. There are some commands i have to remove.

I think i have more than a few cases of this… floor too.
Will check when i can.

Well it’s rather simple, i think. Otherwise i wouldn’t understand it myself :slight_smile: Thinking about it, i think i’ll have to read all of it again, just in case… I tend to never look back.

Thanks for the check, you didn’t have to :slight_smile:

Can some one help me figure out what went wrong here?

All with default setting gives me this error:

C:\Users\User\Pictures\gmic-qt-data\alpha_images>gmic flower.png fx_rep_cbsoo_preview 0,1,0,0,0,1,0,0,0,1,1,0,0,1,1,0,0,0,0,3,100,1,21,100,3,100,1,21,100,1,3,100,1,21,100,1,1,3,100,1,21,100,1,1,3,100,1,21,100,1,1,3,100,1,21,100,1,3,100,1,21,100,1,0,2,2,0,1,"-1"
[gmic]./ Start G'MIC interpreter (v.3.3.4).
[gmic]./ Input file 'flower.png' at position 0 (1 image 300x300x1x4).
[gmic] *** Error in ./fx_rep_cbsoo_preview/*if#7473/*if#7476/ (file 'C:\Users\User\user.gmic', line #7478) *** Operator '+=' on undefined variable 'checked_box'.
#@gui Channel Blur-Sharpen-Overblur-Overline:fx_rep_cbsoo,fx_rep_cbsoo_preview(0)
#@gui:_=separator(),_=note("<b>Color Space Mode</b>")
#@gui:1.8-Bit Color Space=choice(0,"RGB","RYB","CMY/K","HSI","HSL","HSV","LAB","LCH","YCbCr-GLIC","YIQ","YUV","YES",Ohta","Kodak-1")

#@gui:2.Include K Channel=bool(1)

#@gui:3.Contain Gray=bool(0)
#@gui:4.Contain Color=bool(0)
#@gui:5.Contain Alpha=bool(0)

#@gui:_=separator(),_=note("<b>Channel Processing</b>")

#@gui:6.Section=choice(1,"Gray","Color")
#@gui:7.Section=choice(0,"Gray","Alpha")
#@gui:8.Section=choice(0,"Color","Alpha")
#@gui:9.Section=choice(0,"Gray","Color","Alpha")
#@gui:10.Section=choice(1,"Gray","CMY")
#@gui:11.Section=choice(1,"Gray","CMYK")
#@gui:12.Section=choice(0,"CMY","Alpha")
#@gui:13.Section=choice(0,"CMYK","Alpha")
#@gui:14.Section=choice(1,"Gray","CMY","Alpha")
#@gui:15.Section=choice(1,"Gray","CMYK","Alpha")
#@gui:16.Use Section=bool(0)
#@gui:17.Section to Use=int(0,0,3)

#@gui:18.Color Channel=choice(0,"Channel 0","Channel 1","Channel 2")
#@gui:19.Color Channel=choice(0,"Channel 0","Channel 1","Channel 2","Channel 3")

#@gui:20.Method (Linked)=choice(3,"Blur","Sharpen","Overblur","Overline")
#@gui:21.Effect Factor (Linked)=float(100,0,1000)
#@gui:22.Multiplication (Linked)=float(1,.1,10)
#@gui:23.Blend Operation (Linked)=choice(21,"Add","Alpha","AND","Average","Burn","Darken","Difference","Divide","Dodge","Exclusion","Freeze","Grain Extract","Grain Merge","Hardlight","Hard Mix","Interpolation","Lighten","Linear Burn","Linear Light","Multiply","Normal","Negation","OR","Overlay","Pin Light","Reflect","Screen","Shape Average","Soft Burn","Soft Dodge","Soft Light","Stamp","Subtract","Vivid Light","XOR")
#@gui:24.Blend Opacity(%) (Linked)=float(100,.1,100)

#@gui:25.Method=choice(3,"Blur","Sharpen","Overblur","Overline")
#@gui:26.Effect Factor=float(100,0,1000)
#@gui:27.Multiplication=float(1,.1,10)
#@gui:28.Blend Operation=choice(21,"Add","Alpha","AND","Average","Burn","Darken","Difference","Divide","Dodge","Exclusion","Freeze","Grain Extract","Grain Merge","Hardlight","Hard Mix","Interpolation","Lighten","Linear Burn","Linear Light","Multiply","Normal","Negation","OR","Overlay","Pin Light","Reflect","Screen","Shape Average","Soft Burn","Soft Dodge","Soft Light","Stamp","Subtract","Vivid Light","XOR")
#@gui:29.Blend Opacity(%)=float(100,.1,100)
#@gui:30.Enable Gray Channel=bool(1)

#@gui:31.Method=choice(3,"Blur","Sharpen","Overblur","Overline")
#@gui:32.Effect Factor=float(100,0,1000)
#@gui:33.Multiplication=float(1,.1,10)
#@gui:34.Blend Operation=choice(21,"Add","Alpha","AND","Average","Burn","Darken","Difference","Divide","Dodge","Exclusion","Freeze","Grain Extract","Grain Merge","Hardlight","Hard Mix","Interpolation","Lighten","Linear Burn","Linear Light","Multiply","Normal","Negation","OR","Overlay","Pin Light","Reflect","Screen","Shape Average","Soft Burn","Soft Dodge","Soft Light","Stamp","Subtract","Vivid Light","XOR")
#@gui:35.Blend Opacity(%)=float(100,.1,100)
#@gui:36.Enable Channel 0=bool(1)
#@gui:37.Enable Channel Cyan=bool(1)

#@gui:38.Method=choice(3,"Blur","Sharpen","Overblur","Overline")
#@gui:39.Effect Factor=float(100,0,1000)
#@gui:40.Multiplication=float(1,.1,10)
#@gui:41.Blend Operation=choice(21,"Add","Alpha","AND","Average","Burn","Darken","Difference","Divide","Dodge","Exclusion","Freeze","Grain Extract","Grain Merge","Hardlight","Hard Mix","Interpolation","Lighten","Linear Burn","Linear Light","Multiply","Normal","Negation","OR","Overlay","Pin Light","Reflect","Screen","Shape Average","Soft Burn","Soft Dodge","Soft Light","Stamp","Subtract","Vivid Light","XOR")
#@gui:42.Blend Opacity(%)=float(100,.1,100)
#@gui:43.Enable Channel 1=bool(1)
#@gui:44.Enable Channel Magenta=bool(1)

#@gui:45.Method=choice(3,"Blur","Sharpen","Overblur","Overline")
#@gui:46.Effect Factor=float(100,0,1000)
#@gui:47.Multiplication=float(1,.1,10)
#@gui:48.Blend Operation=choice(21,"Add","Alpha","AND","Average","Burn","Darken","Difference","Divide","Dodge","Exclusion","Freeze","Grain Extract","Grain Merge","Hardlight","Hard Mix","Interpolation","Lighten","Linear Burn","Linear Light","Multiply","Normal","Negation","OR","Overlay","Pin Light","Reflect","Screen","Shape Average","Soft Burn","Soft Dodge","Soft Light","Stamp","Subtract","Vivid Light","XOR")
#@gui:49.Blend Opacity(%)=float(100,.1,100)
#@gui:50.Enable Channel 2=bool(1)
#@gui:51.Enable Channel Yellow=bool(1)

#@gui:52.Method=choice(3,"Blur","Sharpen","Overblur","Overline")
#@gui:53.Effect Factor=float(100,0,1000)
#@gui:54.Multiplication=float(1,.1,10)
#@gui:55.Blend Operation=choice(21,"Add","Alpha","AND","Average","Burn","Darken","Difference","Divide","Dodge","Exclusion","Freeze","Grain Extract","Grain Merge","Hardlight","Hard Mix","Interpolation","Lighten","Linear Burn","Linear Light","Multiply","Normal","Negation","OR","Overlay","Pin Light","Reflect","Screen","Shape Average","Soft Burn","Soft Dodge","Soft Light","Stamp","Subtract","Vivid Light","XOR")
#@gui:56.Blend Opacity(%)=float(100,.1,100)
#@gui:57.Enable Channel K=bool(1)

#@gui:58.Method=choice(3,"Blur","Sharpen","Overblur","Overline")
#@gui:59.Effect Factor=float(100,0,1000)
#@gui:60.Multiplication=float(1,.1,10)
#@gui:61.Blend Operation=choice(21,"Add","Alpha","AND","Average","Burn","Darken","Difference","Divide","Dodge","Exclusion","Freeze","Grain Extract","Grain Merge","Hardlight","Hard Mix","Interpolation","Lighten","Linear Burn","Linear Light","Multiply","Normal","Negation","OR","Overlay","Pin Light","Reflect","Screen","Shape Average","Soft Burn","Soft Dodge","Soft Light","Stamp","Subtract","Vivid Light","XOR")
#@gui:62.Blend Opacity(%)=float(100,.1,100)
#@gui:63.Enable Channel Alpha=bool(1)

#@gui:64.Link Channels=bool(0)
#@gui:65.Link Visibility=int(2,0,2)
#@gui:66.Color Space Options=int(2,0,2)
#@gui:67.Make All Channels with same inputs=button(0)

#@gui:68.Total Bools Available=int(1,1,5)
#@gui:69.Stored Variables=text("-1")

fx_rep_cbsoo:
fx_rep_cbsoo_preview:
skip $*

$=arg

cs_choice,include_k=$1,$2
convert_colors_fwd=${arg\ $cs_choice+1,,rgb2ryb,error,rgb2hsi8,rgb2hsl8,rgb2hsv8,rgb2lab8,rgb2lch8,rgb2ycbcrglic,rgb2yiq8,rgb2yuv8,rgb2ohta8,rgb2k18}
convert_colors_bwd=${arg\ $cs_choice+1,,ryb2rgb,error,hsi82rgb,hsl82rgb,hsv82rgb,lab82rgb,lch82rgb,ycbcrglic2rgb,yiq82rgb,yuv82rgb,ohta82rgb,k182rgb}
cmyk_mode,contain_persistent={[$cs_choice==2,narg($_persistent)]}

if $contain_persistent

 _gui_analysis_gray,_gui_analysis_color,_gui_analysis_alpha=${3-5}
 use_section,section_variable,use_link,display_link_checkbox,display_color_space_options,=$16,$17,${64-66}
 stored_variables=$68
 
 temp_check_count_bools,check_count_bools=$67
 if $use_section
  if $section_variable==1 
   section_space=gray,alpha
  else
   if $cmyk_mode 
    ct_text={`('cmyk')[$3+$2]`}
    if $include_k check_count_bools+=1 fi
   else ct_text=color fi
   
   if $section_variable==3   section_space=gray,$ct_text,alpha
   elif $section_variable==2 section_space=$ct_text,alpha
   else                      section_space=gray,$ct_text
   fi
  fi
 fi
 
else

 eval "
  const num_of_imgs=$!;
  contain_gray=contain_color=contain_alpha=0;
  repeat(num_of_imgs,p,
   current_spec_size=s#p;
   if(!contain_gray?current_spec_size<3,contain_gray=1;);
   if(!contain_color?current_spec_size>2,contain_color=1;);
   if(!contain_alpha?current_spec_size==2||current_spec_size>3,contain_alpha=1;);
   if(contain_gray&&contain_color,
    if(contain_alpha,break(););
   );
  );
  set('_gui_analysis_color',contain_color;);
  [contain_gray,contain_alpha];
  "
 _gui_analysis_gray,_gui_analysis_alpha=${}
 
 temp_check_count_bools,check_count_bools=1
 use_section:=sum($_gui_analysis_gray,$_gui_analysis_color,$_gui_analysis_alpha)>1
 if $use_section
  section_list=section_gray_color,section_gray_alpha,section_color_alpha,section_gray_color_alpha
  $section_list:=expr('x',narg($section_list))
  temp_section=section
  
  if $_gui_analysis_gray
   temp_section.=_gray
  fi
  
  if $_gui_analysis_color
   temp_section.=_color
  fi
  
  if $_gui_analysis_alpha
   temp_section.=_alpha
  fi
  
  section_variable=${$temp_section}
  
  if $section_variable==1 
   section_space=gray,alpha
   temp_check_count_bools,check_count_bools=2
  else
  
   if $cmyk_mode ct_text={`('cmyk')[3+$2]`} else ct_text=color fi
   
   if $section_variable==3   section_space=gray,$ct_text,alpha
   elif $section_variable==2 section_space=$ct_text,alpha
   else                      section_space=gray,$ct_text
   fi
   
   temp_check_count_bools,check_count_bools={narg($section_space)+2}
   if $cmyk_mode?$include_k check_count_bools+=1 fi
   
  fi
  
 fi
 
 display_link_checkbox:=($use_section||$_gui_analysis_color)<<1
 use_link:=$display_link_checkbox?$64
 display_color_space_options:=$_gui_analysis_color<<1
 
fi

link_visibility,\
link_effect_visibility,\
gray_visibility,\
gray_effect_visibility,\
display_gray_checkbox,\
channel_0_visibility,\
channel_0_effect_visibility,\
display_channel_0_checkbox,\
display_cyan_checkbox,\
channel_1_visibility,\
channel_1_effect_visibility,\
display_channel_1_checkbox,\
display_magenta_checkbox,\
channel_2_visibility,\
channel_2_effect_visibility,\
display_channel_2_checkbox,\
display_yellow_checkbox,\
black_visibility,\
black_effect_visibility,\
display_black_checkbox,\
alpha_visibility,\
alpha_effect_visibility,\
display_alpha_checkbox,\
section_0_visibility,\
section_1_visibility,\
section_2_visibility,\
section_3_visibility,\
section_4_visibility,\
section_5_visibility,\
section_6_visibility,\
section_7_visibility,\
section_8_visibility,\
section_9_visibility,\
color_3_channels_box_visibility,\
color_4_channels_box_visibility,\
display_k_box,\
allow_link_display,apply_filter=0

temp_section_variable=$section_variable

if $use_section

 if $section_variable!=1&&$cmyk_mode
  selected_section:=$temp_section_variable-($section_variable>1)
  temp_section_variable:=4+($selected_section<<1)+$2
 fi

 section_${temp_section_variable}_visibility=2

 section_space_selection:=([${6-15}])[$temp_section_variable]+1
 section_space=${arg\ $section_space_selection,$section_space}

 if '$section_space'=='color'||'$section_space'=='cmy'
  color_3_channels_box_visibility=2
 elif '$section_space'=='cmyk'
  color_4_channels_box_visibility=2
 fi

elif $_gui_analysis_color
 if $cmyk_mode&&$include_k 
  color_4_channels_box_visibility=2
 else 
  color_3_channels_box_visibility=2
 fi
else use_link=0
fi

if $use_link

 checked_box=0
 link_args=${20-23},$24%
 sep=
 
 if $21 
  apply_filter=1 
 fi

 if $_gui_analysis_gray
  display_gray_checkbox=2
  
  if $30 
   filter_args=$link_args
   checked_box+=1
  else 
   filter_args=-
  fi
  
  sep=,
  
  if '$section_space'=='gray'
   link_effect_visibility:=1+$30
   link_visibility:=($apply_filter?$30)+1
  fi
 fi
 
 if $_gui_analysis_color
  color_channels_checkbox_count=0
  t_filter_args,t_sep=
   
  if $cmyk_mode
   display_cyan_checkbox,display_magenta_checkbox,display_yellow_checkbox=2
   display_black_checkbox:=$include_k<<1
   
   if $37
    t_filter_args.=$link_args
    color_channels_checkbox_count+=1
   else 
    t_filter_args=-
   fi
   
   t_sep=,
   
   if $44
    t_filter_args.=$link_args
    color_channels_checkbox_count+=1
   else 
    t_filter_args.=$t_sep
    t_filter_args.=-
   fi
   
   if $51 
    t_filter_args.=$link_args
    color_channels_checkbox_count+=1
   else 
    t_filter_args.=$t_sep
    t_filter_args.=-
   fi
   
   if $include_k
    if $57
     t_filter_args.=$link_args
     color_channels_checkbox_count+=1
    else 
     t_filter_args.=$t_sep
     t_filter_args.=-
    fi
   fi
   
   if $color_channels_checkbox_count==(3+$include_k)
    t_filter_args=$link_args
   fi
   
   if $use_section?'$section_space'=='cmy'||'$section_space'=='cmyk':1
    pos_choice:=$color_4_channels_box_visibility?$19:$18
    state_chosen_bool:=([$37,$44,$51,$57])[$pos_choice]
    link_effect_visibility:=1+$state_chosen_bool
    link_visibility:=($apply_filter?$state_chosen_bool)+1
    display_k_box=2
   fi
   
   checked_box+=$color_channels_checkbox_count
   filter_args.=$sep$t_filter_args
   sep=,
  else
   display_channel_0_checkbox,display_channel_1_checkbox,display_channel_2_checkbox=2
   
   if $36
    t_filter_args.=$link_args
    color_channels_checkbox_count+=1
   else
    t_filter_args=-
   fi
   
   t_sep=,
   
   if $43
    t_filter_args.=$link_args
    color_channels_checkbox_count+=1
   else
    t_filter_args.=$t_sep
    t_filter_args.=-
   fi
   
   if $50
    t_filter_args.=$link_args
    color_channels_checkbox_count+=1
   else
    t_filter_args.=$t_sep
    t_filter_args.=-
   fi
   
   if $color_channels_checkbox_count==3
    t_filter_args=$link_args
   fi
   
   if $use_section?'$section_space'=='color':1
    state_chosen_bool:=([$36,$43,$50])[$18]
    link_effect_visibility:=1+$state_chosen_bool
    link_visibility:=($apply_filter?$state_chosen_bool)+1
   fi
   
   checked_box+=$color_channels_checkbox_count
   filter_args.=$sep$t_filter_args
   sep=,
  fi
 fi
 
 if $_gui_analysis_alpha
  display_alpha_checkbox=2
  
  if $63 
   filter_args.=$sep$link_args
   checked_box+=1
  else
   filter_args.=$sep
   filter_args.=-
  fi
  
  if '$section_space'=='alpha'
   link_effect_visibility:=1+$63
   link_visibility:=($apply_filter?$63)+1
  fi
 fi
 
 if $checked_box==$check_count_bools filter_args=$link_args fi
else
 all_args_same=0,1
 previous_args=n/a
 sep=
 
 if $_gui_analysis_gray
  if $30
   previous_args=${25-28},$29%
   if $26 apply_filter=1 fi
  else
   previous_args=-
   all_args_same=0
  fi
  
  gray_args,filter_args=$previous_args
  sep=,
  
  if $use_section?'$section_space'=='gray':1
   gray_effect_visibility:=1+$30
   gray_visibility:=($30?$26)+1
   display_gray_checkbox=2
  fi
 fi
 
 if $_gui_analysis_color
  local_all_args_same=1
  
  if $cmyk_mode
   if $37
    current_args=${31-34},$35%
    if $32 apply_filter=1 fi
   else
    current_args=-
    local_all_args_same=all_args_same=0
   fi
   
   t_filter_args,previous_args=$current_args
   
   if $44
    current_args=${38-41},$42%
    if $local_all_args_same local_all_args_same={'$current_args'=='$previous_args'} fi
    if $39 apply_filter=1 fi
   else
    current_args=-
    local_all_args_same=all_args_same=0
   fi
   
   t_filter_args.=,$current_args
   previous_args=$current_args
   
   if $51
    current_args=${45-48},$49%
    if $local_all_args_same local_all_args_same={'$current_args'=='$previous_args'} fi
    if $46 apply_filter=1 fi
   else
    current_args=-
    local_all_args_same=all_args_same=0
   fi
   
   t_filter_args.=,$current_args
   previous_args=$current_args
   
   if $include_k
    if $57
     current_args=${52-55},$56%
     if $local_all_args_same local_all_args_same={'$current_args'=='$previous_args'} fi
     if $53 apply_filter=1 fi
    else
     current_args=-
     local_all_args_same=all_args_same=0
    fi
    
    t_filter_args.=,$current_args
    previous_args=$current_args
   fi
   
   if $local_all_args_same
    if $_gui_analysis_gray
     if '$gray_args'!='$previous_args' all_args_same=0 fi
    fi
   else all_args_same=0
   fi
   
   if $use_section?'$section_space'=='cmy'||'$section_space'=='cmyk':1
    pos_choice:=$color_4_channels_box_visibility?$19:$18
    state_chosen_bool,state_chosen_effect:=([$37,$33,$44,$39,$51,$46,$57,$53])[$pos_choice<<1,2]
    channel_${pos_choice}_effect_visibility=1+$state_chosen_bool
    channel_${pos_choice}_visibility:=($state_chosen_bool?$state_chosen_effect)+1
    channel_name=${arg\ $pos_choice,cyan,magenta,yellow,black}
    display_${channel_name}_checkbox=2
   fi
   
  else
   if $36
    current_args=${31-34},$35%
    if $32 apply_filter=1 fi
   else
    current_args=-
    local_all_args_same=all_args_same=0
   fi
   
   t_filter_args,previous_args=$current_args

   if $43
    current_args=${38-41},$42%
    if $local_all_args_same local_all_args_same={'$current_args'=='$previous_args'} fi
    if $39 apply_filter=1 fi
   else
    current_args=-
    local_all_args_same=all_args_same=0
   fi
   
   t_filter_args.=,$current_args
   previous_args=$current_args
   
   if $50
    current_args=${45-48},$49%
    if $local_all_args_same local_all_args_same={'$current_args'=='$previous_args'} fi
    if $46 apply_filter=1 fi
   else
    current_args=-
    local_all_args_same=all_args_same=0
   fi
   
   t_filter_args.=,$current_args
   previous_args=$current_args
   
   if $local_all_args_same
    if $_gui_analysis_gray
     if '$gray_args'!='$previous_args' all_args_same=0 fi
    fi
    t_filter_args=$previous_args
   else all_args_same=0
   fi
   
   if $use_section?'$section_space'=='color':1
    state_chosen_bool,state_chosen_effect:=([$36,$32,$43,$39,$50,$46])[$19<<1,2]
    channel_$19_effect_visibility:=1+$state_chosen_bool
    channel_$19_visibility:=($state_chosen_bool?$state_chosen_effect)+1
    display_channel_$19_checkbox=2
   fi
  fi
 fi
 
 if $_gui_analysis_alpha
  if $63
   current_args=${58-61},$62
   if $59 apply_filter=1 fi
  else
   current_args=-
   all_args_same=0
  fi
  
  if '$current_args'!='$previous_args'
   all_args_same=0
  fi
  
  
  filters_args.=,$current_args
  
  if '$section_space'=='alpha'
   alpha_effect_visibility:=1+$63
   alpha_visibility:=($63?$58)+1
   display_alpha_checkbox=2
  fi
 fi
 
 if $all_args_same filters_args=$current_args fi
fi

_persistent=1
return

u "{$1}"_$display_color_space_options\
"{$2}"_$display_color_space_options\
"{"$_gui_analysis_gray"}"\
"{"$_gui_analysis_color"}"\
"{"$_gui_analysis_alpha"}"\
"{$6}"_$section_0_visibility\
"{$7}"_$section_1_visibility\
"{$8}"_$section_2_visibility\
"{$9}"_$section_3_visibility\
"{$10}"_$section_4_visibility\
"{$11}"_$section_5_visibility\
"{$12}"_$section_6_visibility\
"{$13}"_$section_7_visibility\
"{$14}"_$section_8_visibility\
"{$15}"_$section_9_visibility\
"{"$use_section"}"\
"{"$section_variable"}"\
"{$18}"_$color_3_channels_box_visibility\
"{$19}"_$color_4_channels_box_visibility\
"{$20}"_$link_visibility\
"{$21}"_$link_effect_visibility\
"{$22}"_$link_visibility\
"{$23}"_$link_visibility\
"{$24}"_$link_visibility\
"{$25}"_$gray_visibility\
"{$26}"_$gray_effect_visibility\
"{$27}"_$gray_visibility\
"{$28}"_$gray_visibility\
"{$29}"_$gray_visibility\
"{$30}"_$display_gray_checkbox\
"{$31}"_$channel_0_visibility\
"{$32}"_$channel_0_effect_visibility\
"{$33}"_$channel_0_visibility\
"{$34}"_$channel_0_visibility\
"{$35}"_$channel_0_visibility\
"{$36}"_$display_channel_0_checkbox\
"{$37}"_$display_cyan_checkbox\
"{$38}"_$channel_1_visibility\
"{$39}"_$channel_1_effect_visibility\
"{$40}"_$channel_1_visibility\
"{$41}"_$channel_1_visibility\
"{$42}"_$channel_1_visibility\
"{$43}"_$display_channel_1_checkbox\
"{$44}"_$display_magenta_checkbox\
"{$45}"_$channel_2_visibility\
"{$46}"_$channel_2_effect_visibility\
"{$47}"_$channel_2_visibility\
"{$48}"_$channel_2_visibility\
"{$49}"_$channel_2_visibility\
"{$50}"_$display_channel_2_checkbox\
"{$51}"_$display_yellow_checkbox\
"{$52}"_$black_visibility\
"{$53}"_$black_effect_visibility\
"{$54}"_$black_visibility\
"{$55}"_$black_visibility\
"{$56}"_$black_visibility\
"{$57}"_$display_black_checkbox\
"{$58}"_$alpha_visibility\
"{$59}"_$alpha_effect_visibility
"{$60}"_$alpha_visibility\
"{$61}"_$alpha_visibility\
"{$62}"_$alpha_visibility\
"{$63}"_$display_alpha_checkbox\
"{"$use_link"}"_$display_link_checkbox\
"{"$display_link_checkbox"}"\
"{"$display_color_space_options"}"\
"{$67}"\
"{$68}"\
"{$69}"

All I know that there’s a misplaced fi, but where?