Reptorian G'MIC Filters

Easiest way is with the built in srgb2rgb and rgb2srgb. Example from an existing filter:

#@cli gcd_dither_srgb : _nb_levels>=2
#@cli : Dither selected sRGB images.
#@cli : Default values: 'nb_levels=2'.
#@cli : $ image.jpg gcd_dither_srgb 6 round
gcd_dither_srgb : check "isint(${1=2}) && $1>=2"
  repeat $! l[$>]
    s c (0,255) r. $1,1,1,1,3
    srgb2rgb index[^-1] .,1,1 rm. a c rgb2srgb
  done done
1 Like

Even more news, I managed to add a option in which the command grabs the nearest set of color before processing the image. It’s different than internal processing of indexing. The reason why I did this was the existence of TO7/70 mode. Also, it seems that the command is nearly done.

I’m using 8-Bit Labs for Android as my inspiration. I do wish I can do ordered dithering version though, but that comes much later.

Here’s what I mean:

Pre-process autoselect nearest colors:

Without pre-process autoselect nearest colors:

The difference is pretty clear. There are 2 colors per window for both, but the difference in the first one is that the entire image consists of only n colors.

It also works for alpha, but that is on work too:

Saving my work here as backup:

Current Transfer Color (Reduced Color)
###########
#         #
#  Start  #
#         #
###########

# gmic i test_image.png +pal srb2 tic rep_transfer_color_reduced[0] [1],.5,3,2,8,8,4,,10,1,1 rm.
# gmic sp cat +pal 56 rep_transfer_color_reduced[0] [1],.5,3,2,8,8,4,0,16,.5,0

# rep_transfer_color_reduced has been completed without ordered dithering.
# TODO: Do ordered dithering.

#@cli rep_transfer_color_reduced:
#@cli : Change images to look as if it was reduced. Can be used to emulate old hardware.
rep_transfer_color_reduced:
skip ${2=0},${3=0},${4=0},${5=0},${6=0},${7=0},${8=0},${9=},${10=.5},${11=0},${12=0}

pass$1 0

if s==2||s>4 error inv_pal_inp fi

use_alpha_remap=0

if narg($9)
 number_of_alpha_band={min(max(2,int(abs($9))),255)}
 if ($9!=0)&&$number_of_alpha_band<255 use_alpha_remap=1 fi
fi

if $use_alpha_remap

 $number_of_alpha_band,1,1,1,"begin(
   const rescale=(w-1)/255;
  );
  x/rescale"
  
  round. 0
  
  _rep_transfer_color_reduced[0--3] [-2],${2-8},[-1],${10-12}
  
  rm.
  
else

 _rep_transfer_color_reduced[^-1] [-1],${2-8},,${10-12}
 
fi

rm.

_rep_transfer_color_reduced:
skip ${2=0},${3=0},${4=0},${5=0},${6=0},${7=0},${8=0},${9=},${10=.5},${11=0},${12=0}

# color_palette = $1
# color_dither = $2

# pixel_ratio_w,pixel_ratio_h,window_width,window_height,color_restriction_per_window,color_restriction_whole,number_of_alpha,alpha_dithering,alpha_mode,alpha_restrict

pixel_ratio_w,pixel_ratio_h={int(abs([$3,$4]))}
window_width,window_height={int(abs([$5,$6]))}
color_restriction_per_window,color_restriction_whole={v=int(abs($7));v?max(2,v):0;},{v=int(abs($8));v?max(2,v):0}

if $color_restriction_per_window<=$color_restriction_whole color_restriction_per_window=0 fi

dec_color_restriction_whole={$color_restriction_whole-1}

alpha_dithering={cut($10,0,1)}
alpha_mode=${is_image_arg\ $9}
alpha_mode={($11%2)+$alpha_mode}
adj_alpha_map={$alpha_mode?1}

pixel_ratio_gcd={gcd($pixel_ratio_w,$pixel_ratio_h)}

if $pixel_ratio_gcd>1 pixel_ratio_w,pixel_ratio_h/=$pixel_ratio_gcd fi

pass$1 0

activate_window_based_indexing={($color_restriction_per_window<whd#-1)&&($window_width>1||$window_height>1)}
activate_create_restricted_palette={$color_restriction_whole?$color_restriction_whole<whd#-1}

if h#-1>1&&w#-1==1 rotate. 90
elif h#-1>1||d#-1>1 colormap. 0
fi

if s==2||s==4 remove_opacity. fi

if s==1
 foreach[^-1] {
  if s>2
   if s==3 to_gray
   else to_graya
   fi
  fi
 }
fi

store. palette_image

if narg($9)&&$alpha_mode
 pass$9 0
 store. alpha_image
 process_alpha=1
 alpha_restriction_per_window={$12?min(int(abs($12)),w#-1):$color_restriction_per_window}
else
 adj_alpha_map=0
fi

if $pixel_ratio_w==1||$pixel_ratio_h==1
 initial_rescale_w,initial_rescale_h={bd=max($pixel_ratio_w,$pixel_ratio_h);100*($pixel_ratio_w>$pixel_ratio_h?vector(#2,1)/[bd,1]:vector(#2,1)/[1,bd])}
else
 min_dimension,max_dimension={min($pixel_ratio_w,$pixel_ratio_h)},{max($pixel_ratio_w,$pixel_ratio_h)}
 recip_rd={1/($max_dimension/$min_dimension)}
 initial_rescale_w,initial_rescale_h={100*($pixel_ratio_w>$pixel_ratio_h?[$recip_rd,1]:[1,$recip_rd])}
fi
 
foreach {
 
 if s>4 continue fi
 
 $palette_image
  
 num_of_color_chans_in_target_image={!(s#0%2)?(s#0-1):s#0}
 dec_num_of_color_chans_in_target_image={$num_of_color_chans_in_target_image-1}
  
 if $num_of_color_chans_in_target_image<s to_gray. fi
    
 use_alpha_map={$adj_alpha_map&&!(s#0%2)}
 
 resize[-2] $initial_rescale_w%,$initial_rescale_h%,100%,100%,3
  
 if $activate_create_restricted_palette
  sh[0] 0,$dec_num_of_color_chans_in_target_image
  +index[-1] [1],$2,0
  histogram. 100%
  {w},1,1,1,x
  pixelsort. -,x,..
  crop. 0,0,$dec_color_restriction_whole,0
  map. [-4]
  k[0,-1]
 fi
  
 if $activate_window_based_indexing
  
  sh[0] 0,$dec_num_of_color_chans_in_target_image
  rep_index_by_window_and_color_restriction[-1] [-2],$2,$color_restriction_per_window,$window_width,$window_height,1,1 
  rm.
   
  if $use_alpha_map
   sh[0] {s#0-1}
   $alpha_image
   if $alpha_mode==2 rep_index_by_window_and_color_restriction[-2] [-1],$2,$alpha_restriction_per_window,$window_width,$window_height,1,1 
   else index[-2] [-1],$2,1
   fi
   rm[-2,-1]
  fi
   
 else
  
  sh[0] 0,$dec_num_of_color_chans_in_target_image
  index[-1] [-2],$2,1
  rm.
   
  if $use_alpha_map
   sh[0] {s#0-1}
   $alpha_image
   index[-2] [-1],$2,1
   rm[-2,-1]
  fi
   
 fi
  
 resize[0] {$pixel_ratio_w*100}%,{$pixel_ratio_h*100}%,100%,100%,1
  
 k[0]
  
} 
 

###########
#         #
# END-FIN #
#         #
###########

###########
#         #
#  Start  #
#         #
###########

#@cli rep_index_by_window_and_color_restriction:[palette],0<=_dithering<=1,_color_restriction>2,_window_width,_window_height,_window_depth,_map_palette={ 0 | 1 }
#@cli : Index images per window
rep_index_by_window_and_color_restriction:

dithering,col_res,wi_w,wi_h,wi_d,map_palette,timg={cut($2,0,1)},{cut(int(abs($3)),2,w#-1)},{vmax(vector(#3,1),int(abs([${4-6}])))},{$7%2},{$!}

dec_col_res={$col_res-1}

pass$1 1

if h#-1>1&&d#-1==1
 rm. pass$1 0
 rotate. -90
elif h#-1>1&&d#-1>1
 rm. pass$1 0
 colormap. 0,,0
fi

if $dithering
 
 # Jarvis, Judice, and Ninke dithering Array
  jjn_1R0D,jjn_2R0D,\
  jjn_2L1D,jjn_1L1D,jjn_M01D,jjn_1R1D,jjn_2R1D,\
  jjn_2L2D,jjn_1L2D,jjn_M02D,jjn_1R2D,jjn_2R2D\
  ={([7,5,3,5,7,5,3,1,3,5,3,1]/48)*$dithering}
 
fi

eval "
  const spectrum_size=s#-1;
  const rf=$timg;
  valid_spec=1;
  repeat(rf,id,
   if(s#id!=spectrum_size,valid_spec=0;break(););
  );
  valid_spec;
 "
 
if !${} error incompatible_img_pal fi

if $col_res>=w#-1
 index[^-1] [-1],$dithering,$map_palette
 rm.
 return
fi

repeat $timg local[$>,-1] 
 {
 
  ow,oh,od,tw,th,td,nw,nh,nd={od=[w#0,h#0,d#0];wd=vmin([w#0,h#0,d#0],[$wi_w,$wi_h,$wi_d]);td=ceil(od/wd);nd=td*wd;[od,td,nd]}

  
  if [$tw,$th,$td]==vector(#3,1)
   +index[0] [1],1,0
   histogram. 100%
   {w},1,1,1,x
   pixelsort. -,x,..
   crop. 0,0,$dec_col_res,0
   map. ...
   index[0] .,$dithering,$map_palette
  else
  
   r[0] $nw,$nh,$nd,100%,0,3,.5,.5,.5
  
   +index[0] [1],{$dithering?.75},0
  
   $tw,$th,$td,1,*"begin(
     const nb_cols=w#1;
    
     const spectrum_size=s#1;
     const inc_spectrum_size=spectrum_size+1;
    
     const nb_restrict=$col_res;
     const dec_nb_restrict=nb_restrict-1;
    
     const res_y_spec=nb_restrict*spectrum_size;
    
     const wi_w=$wi_w;
     const wi_h=$wi_h;
     const wi_d=$wi_d;
    
     const dec_wi_w=wi_w-1;
     const dec_wi_h=wi_h-1;
     const dec_wi_d=wi_d-1;
    
     const box_dim=wi_w*wi_h*wi_d;
    
     init_freq_y_ind=expr('(x%2)?int(x/2);',nb_cols*2);
     init_sel_res_pal_dist_arr=vector(#nb_restrict,0);
    
     const dithering_mode=$dithering;
     const map_palette=$map_palette;
    
     dithering_mode?(
    
      #                            jjn_1R0D jjn_2R0D
      # jjn_2L1D jjn_1L1D jjn_M01D jjn_1R1D jjn_2R1D
      # jjn_2L2D jjn_1L2D jjn_M02D jjn_1R2D jjn_2R2D
     
      const jjn_1R0D=$jjn_1R0D;
      const jjn_2R0D=$jjn_2R0D;
      const jjn_2L1D=$jjn_2L1D;
      const jjn_1L1D=$jjn_1L1D;
      const jjn_M01D=$jjn_M01D;
      const jjn_1R1D=$jjn_1R1D;
      const jjn_2R1D=$jjn_2R1D;
      const jjn_2L2D=$jjn_2L2D;
      const jjn_1L2D=$jjn_1L2D;
      const jjn_M02D=$jjn_M02D;
      const jjn_1R2D=$jjn_1R2D;
      const jjn_2R2D=$jjn_2R2D;
     
      v_col()=I(#2,pos_x,pos_y,pos_z);
     
      # gen_res_pal_col();
     
      map_palette?(
       result_img_part()=(
        old_color=I(#0,pos_x,pos_y,pos_z);
        new_color=I(#1,res_col_id[argmin(sqrt(res_color_sum))],0,0);
      
        I(#0,pos_x,pos_y,pos_z)=new_color;
       );
      ):(
       result_img_part()=(
        old_color=I(#0,pos_x,pos_y,pos_z);
        new_color_pos=res_col_id[argmin(sqrt(res_color_sum))];
        new_color=I(#1,new_color_pos,0,0);
      
        i(#0,pos_x,pos_y,pos_z,0)=new_color_pos;
       );
      );
     
      result_img()=(
       result_img_part();
       diff_color=old_color-new_color;
      
       use_strip_1D=(pos_y+1)<min_out_of_boundary_offset_pos[2];
       use_strip_2D=(pos_y+2)<min_out_of_boundary_offset_pos[2];
      
       use_strip_1D?(
        I(#0,pos_x,pos_y+1,pos_z)+=diff_color*jjn_M01D;
       );
      
       use_strip_2D?(
        I(#0,pos_x,pos_y+2,pos_z)+=diff_color*jjn_M02D;
       );
      
       (pos_x-2)>min_out_of_boundary_offset_pos[0]?(
        use_strip_1D?(
         I(#0,pos_x-2,pos_y+1,pos_z)+=diff_color*jjn_2L1D;
        );
        use_strip_2D?(
         I(#0,pos_x-2,pos_y+2,pos_z)+=diff_color*jjn_2L2D;
        );
       );
      
       (pos_x-1)>min_out_of_boundary_offset_pos[0]?(
        use_strip_1D?(
         I(#0,pos_x-1,pos_y+1,pos_z)+=diff_color*jjn_1L1D;
        );
        use_strip_2D?(
         I(#0,pos_x-1,pos_y+2,pos_z)+=diff_color*jjn_1L2D;
        );
       );
      
       (pos_x+1)<min_out_of_boundary_offset_pos[1]?(
        I(#0,pos_x+1,pos_y,pos_z)+=diff_color*jjn_1R0D;
        use_strip_1D?(
         I(#0,pos_x+1,pos_y+1,pos_z)+=diff_color*jjn_1R1D;
        );
        use_strip_2D?(
         I(#0,pos_x+1,pos_y+2,pos_z)+=diff_color*jjn_1R2D;
        );
       );
       
       (pos_x+2)<min_out_of_boundary_offset_pos[1]?(
        I(#0,pos_x+2,pos_y,pos_z)+=diff_color*jjn_2R0D;
        use_strip_1D?(
         I(#0,pos_x+2,pos_y+1,pos_z)+=diff_color*jjn_2R1D;
        );
        use_strip_2D?(
         I(#0,pos_x+2,pos_y+2,pos_z)+=diff_color*jjn_2R2D;
        );
       ); 
       
      );
     
     ):(
    
      v_col()=I(#0,pos_x,pos_y,pos_z);
     
      # gen_res_pal_col();
      
      map_palette?(
       result_img()=(
        I(#0,pos_x,pos_y,pos_z)=I(#1,res_col_id[argmin(sqrt(res_color_sum))],0,0);
       );
      ):(
       result_img()=(
        i(#0,pos_x,pos_y,pos_z,0)=res_col_id[argmin(sqrt(res_color_sum))];
       );
      );
     );
    
    
    );
   
    c_xp=x*wi_w;
    c_yp=y*wi_h;
    c_zp=z*wi_d;
   
    min_out_of_boundary_offset_pos=[c_xp,c_xp,c_yp]+[-1,wi_w,wi_h];
   
    freq_y_ind=init_freq_y_ind;
    
    tv=crop(#2,c_xp,c_yp,c_zp,0,wi_w,wi_h,wi_d,1);
    
    repeat(box_dim,k,
     ++freq_y_ind[tv[k]*2];
    );
   
    freq_y_ind=sort(freq_y_ind,0,nb_cols,2);
    res_col_id=(freq_y_ind)[1,nb_restrict,2];
   
    res_pal=vector(#res_y_spec,0);
    
    repeat(nb_restrict,p,
     res_pal_col=I(#1,res_col_id[p],0,0);
     repeat(spectrum_size,q,
      res_pal[q*nb_restrict+p]=res_pal_col[q];
     );
    );
   
    repeat(wi_d,oz,
     pos_z=c_zp+oz;
    
     repeat(wi_h,oy,
      pos_y=c_yp+oy;
     
      repeat(wi_w,ox,  
       pos_x=c_xp+ox;
      
       res_color_sum=init_sel_res_pal_dist_arr;
       v_col=I(#0,pos_x,pos_y,pos_z);
      
       repeat(spectrum_size,k,
        res_color_sum+=sqr((res_pal)[k*nb_restrict,nb_restrict]-v_col[k]);
       );
      
       result_img();
       
      );
     );
    );
    0;
    "
   
   if !$map_palette channels[0] 0 fi
   
   crop[0] {od=[$ow,$oh,$od];op=[$nw,$nh,$nd]-od;[op,vsum(od,op)-1];}
  fi
  
  k[0,1]
 }
done

rm.

 
###########
#         #
# END-FIN #
#         #
###########

###########
#         #
#  Start  #
#         #
###########

#@cli +rep_bayer_threshold_map: iteration,normalize
#@cli : Create Bayer Threshold Map
+rep_bayer_threshold_map:
ws=2

(0,2;3,1)
+store. initial_map

repeat $1 {

 ws*=2
 
 $initial_map
 
 $ws,$ws
 
 eval[-2] "begin(
   const ws=$ws;
   const half_ws=ws>>1;
   initial=crop(#-3);
  );
  M_Surface=initial*4;
  M_Surface+=i;
  draw(#-1,M_Surface,x*half_ws,y*half_ws,0,0,half_ws,half_ws,1,1);
  "
 
 rm[-3,-2]
 
}

###########
#         #
# END-FIN #
#         #
###########

The bayer matrix thing, well, I’m doing ordered dithering, any assistance could be nice as I have no idea what I’m doing. The matrix works though. See here for details: Ordered dithering - Wikipedia

Here’s the 8x8 matrix:

image

I suppose you have it already, but you can generate the map with something like:

gcd_dith_map : skip ${1=1}
  (0) l. {
    repeat $1 {
      *[0] 4 ++[0] 2 ++[0] 3 ++[0] 1
      a[0,1] x a[1,2] x a y
    }
  } * {4^-$1}
2 Likes

It’s not the map that’s the problem, it’s using the map to generate color that’s the problem. Right now, my algorithm is less than stellar.

Reptorian's ordered dithering algorithm
#@cli rep_ordered_dithering: bit_depth,threshold_map_iteration
#@cli : Apply ordered dithering effect onto image.
rep_ordered_dithering:
+rep_bayer_threshold_map $2

f[^-1] "begin(
  const n=w#-1-1;
  const bit_depth=max( 1, int( abs($1) ) );
  const scale=255/bit_depth;
  const r=255/(2^bit_depth);
 );
 mx=x&n;
 my=y&n;
 m=i(#-1,mx,my,0,0);
 c=round((I+r*m)/scale)*scale;
 "


###########
#         #
# END-FIN #
#         #
###########

###########
#         #
#  Start  #
#         #
###########

#@cli +rep_bayer_threshold_map: iteration,_normalize
#@cli : Create Bayer Threshold Map
+rep_bayer_threshold_map:
skip ${2=1}

ws=2

(0,2;3,1)
+store. initial_map

repeat $1 {

 ws*=2
 
 $initial_map
 
 $ws,$ws
 
 eval[-2] "begin(
   const ws=$ws;
   const half_ws=ws>>1;
   initial=crop(#-3);
  );
  M_Surface=initial*4;
  M_Surface+=i;
  draw(#-1,M_Surface,x*half_ws,y*half_ws,0,0,half_ws,half_ws,1,1);
  "
 
 rm[-3,-2]
 
}

if $2

 +. 1
 /. {4^($1+1)}
 -. {ia#-1}
 
fi

Output:

I will give it that it does look retro, but not quite good.

Gradient map looks like this :

After this is figured out, I’ll try to figure out how to exactly do the palette version.

@afre I’m requesting a quick test as you run a slow computer. I made this recent commit:

Run ' $ tic +rep_find_permutation 8 toc ', then tell me the time it takes to finish. To me, it takes .008 s. But, your time will make me decide if I should code it a base64 img of it for my other gmic file.

I think I will limit it to 10 max. 11 is just way too slow because 11! is equal to 39,916,800. Takes me 7.5 s. Done. Limited to 10.

Version 3.1.2 # NOOOOO! My local files have been
              # rejected due to recent changes!
11.623 s      # Timing for your command
 5.184 s      # Timing with lower verbosity

PS - doesn’t appear to represent your latest 2 commits!

PPS - updated gmic and now the command is zippy (0.019 s). Doesn’t have stdout. Instead, I get a display window.

I.e., with

tic +rep_find_permutations 8 toc

1 Like

@afre Thanks, afre. That seem to confirm that it is useful in some cases other than building strings with it.



In light of permutations thing, I have released two permutations commands rep_extract_permutation_order, and rep_find_permutation_lexicographic_index.

Here how they work, let’s use rep_find_permutations and see what it yields:

$ +rep_find_permutations 5 echo {I(#-1,80)}
=> 3,1,2,0,4

The command rep_find_permutations creates all the 720 possible order, and they are all sorted in lexicographic order. The math parser access index 80, and the resulting output is what it yields.

As for the 5, well, that is the number of items variable.

Let’s try rep_extract_permutation_order and see what it yields:

$ rep_extract_permutation_order 5,80 echo ${}
=> 3,1,2,0,4

The result are the same? Huh, so what’s the difference? The difference is that this command doesn’t generate all of the permutation, it goes straight into finding out what could be the order at index n. And I know there’s the question of what the 5 means. Well, that is the number of items.

Let’s try rep_find_permutation_lexicographic_index and see what it yields. (To use this command, just reorder a list of integer starting from 0, and the number of integer is the number of items):

$ rep_find_permutation_lexicographic_index 3,1,2,0,4 echo ${}
=> 80

With the above note, this is self-explanatory. It finds which index contains the following order.

These new commands does not generate all of the combinations, so you can literally access billions of index.

This means in theory, you can use those commands to reorder images, and blend them multiple ways.

EDIT: I pushed Bit-Plane Shuffler upgrade. This demonstrates the use of those commands. Preview still needs work, but I will get to that later. Regardless, it is accurate.


On Ordered Dithering:

I finally figured how to make it look nice:

Here’s the 1-bit version:

image

I’m inching closer to adding hundreds of new palettes to +pal command. I’m actually using Python to create the G’MIC code. Possibly even thousand is possible.

EDIT: I settled to 379 palette. I’m actually going to sort palettes with a image editor, then export to ora to get the index. It is incredibly boring to do that though as I’m sorting 130+ new palettes, and some few existing ones. But, the reward is worth it.

EDIT: I have finished sorting it the way that I like. That was tedious, but this image shows there’s more flexibility within the palette list.

If you look closely, you’d note that there are some deliberate sorting of tone/coloring, and there was also naming order, etc. Basically a mixture of orders.

Now, I finished up and added 155 palettes to gmic-community. So, users can now choose up to 379 palettes.

Seems like a huge effort you put in!

Is this all rolled into the cli command pal? If so, two suggestions:

  1. Add some help output so you can do gmic h pal
  2. Consider adding a prefix since it’s such a short name (it could collide with others local gmic quite easily since it’s not documented stdlib)

Yes, it’s rolled in one command.

This is already added. It’s gmic h +pal. David_Tschumperle has added the specialization of +command.



This I don’t know about. With my Premade Palette GUI filter, the help documentation provided there might look ugly. And that’s also why I have added so many palettes. There’s rainbow palettes, there’s gradients palettes, there’s hardware-based palette, there’s software palette, there’s existing game palette, there’s desaturated palette, there’s palette of each color, and there’s speciality palette like Human Faces. Basically just about everything though I wish I could do some more.

I see, that does seem confusing to me to define +pal without also defining pal. Even if it’s only a stub which calls the other (take a look at mse for example).

The thing I consider about taking short command names is it reduces options for others. Example:

# in community file
long_command_name_pal : skip 0
# in local file
pal : long_command_name_pal # I can shorthand alias it
pal : e "do something else" # OR use my own pal AND the community one

With short names:

# in community file
pal : skip 0
# local file
# I want to use pal myself locally, but it's taken!
pal : e "hi" # redefined, but now I can't use community pal any more!

It’s not a disaster, but it limits what other people can do (unless there’s a workaround I didn’t think of!).

Edit: I guess I should add that since commands are redefined silently, if you’re also using pal inside your other commands, it could cause them to break in unexpected ways if somebody has their own pal command. The more unique you can make them the better.

Community commands should have a prefix. This has another benefit not yet mentioned: we know who the author is. Instead of having users bother David about an error or request, we know who to direct it. If David sees it fit, he can always link your command to a non-prefixed name or integrate it into core.

Whatever you decide to do, your hard work is appreciated for sure!

As far as I see, this “+pal” custom function comprises of more than 760 (sub-) custom functions!
Maybe a “long_command_name_pal” with “long_command_ name” sub-custom functions could be some test for the implementation quality of the gmic script processor!
Actually there are about 4800 custom functions in update313.gmic shown by my lightweight grep ^[a-z_+][a-z0-9_]* *:{1,1}[^=].*$ with about 2300 custom functions from gmic_stdlib and about 450 pal related functions.
update313.gmic seems to be not actual, it does not reflect the actual gmic-community files!

1 Like

It would be better indeed not to define too much subfunctions for a single commands. Because all these sub-commands are added to the pool of commands the interpreter has to check when parsing any item of a gmic script.
To be clear : the more commands, the more time spent to parse and analyze a gmic script. Having lot of commands slows down everything.

So, to reduce the number of subcommands, I should switch to if else format or use command merge within these command? Or maybe a new command that acts like a switch statement based on number rather than if/else? On the new command idea, basically G’MIC finds the position argument then parse command that matches position argument. Or a use arg and a lot of base64 codes?

In your case, I would suggest a completely different approach.
As you basically have a (big) image list of palettes, it could be interesting to compress the whole list, and encode it as a base64 string.
After that, command pal would only have to decompress the list and return the $1^th index of the list as an image.

To compress your list of palettes:

repeat 223 pal $> done serialize auto,1,1 img2base64 e ${}

Then, copy/paste the displayed string, and put it somewhere in your reptorian_b64_repository.gmic file:

+_pal_b64 : 
  base642img "..your base64 string here.."

Then, pal becomes basically:

+pal : l[] { _pal_b64 k[$1] }

That’s clearly the more efficient way of storing all your palettes, without requiring to access to an external data file (something that clut does for instance).

More precisely, something like this:

+pal :
  l[] {
    l[] $_pal onfail
      base642img "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"
      +store. _pal
    }
    k[{$1%$!}]
  }

EDIT: This whole command takes around 30Kb.