Reptillian Posted December 9, 2019 Share Posted December 9, 2019 (edited) Even though I have done this sort of thing for G'MIC-QT as a cli command, I decided to make it as a plugin just out of doing something different. What this plugin does is modulo functions, but on the end of modulo expression, the value is added by 1. Essentially useful for gradient map preparation, and that's the main reason why this exist. It can also be used for glitch art. Plugin Download - Image Modulo Toolkit.zip - ( Added new features in 10/09/2020 - Clipboard, Invert ) After you install the plugin, it's under Adjustments menu. Here's examples of how it works using various Mode option and 64 as the maximum resulting number. Target Image Regular Modulo Regular Modulo Continuous Divisive Modulo Divisive Modulo Continuous Modulo Addition Modulo Addition Continuous ------------- Introduction to new features Clipboard - The main purpose of using this is to create new gradients from existing gradient. Invert* - Before - - After - Invert* = This is mainly used to choose darkening option over lightening option in case of Modulo Addition series ------------- Special note : I will not be adding features to this plugin. If you want to add features, you are welcome to do so and post it in this thread. Otherwise, I will refer you to my g'mic-qt filter which is Modulus Operations which is under Testing->Reptorian License : GPLv3 - Source codes - CodeLab // Name: Image Modulo Toolkit // Submenu: Adjustment // Author: Reptorian // Title: Image Modulo Toolkit // Version: 2 // Desc: Adjust image values based on I%(Amount+1) // Keywords: Modulo // URL: // Help: #region UICode ListBoxControl<ModuloMode> moduloMode = ModuloMode.Modulo; // Mode | Modulo | Modulo Continuous | Divisive Modulo | Divisive Modulo Continuous | Modulo Addition | Modulo Addition Continuous IntSliderControl maxNumber = 255; // [1,255] {!ClipboardMode} Maximum Number CheckboxControl ClipboardMode = false; // Use Clipboard CheckboxControl Negate = false;// Invert #endregion // m_clip surface Surface m_clip = null; Surface m_maxNum = null; private Surface clipboardSurface = null; private bool readClipboard = false; protected override void OnDispose(bool disposing) { if (disposing) { if (m_clip != null) m_clip.Dispose(); m_clip = null; if (clipboardSurface != null) clipboardSurface.Dispose(); clipboardSurface = null; } base.OnDispose(disposing); } void PreRender(Surface dst, Surface src) { int R1,G1,B1,R2,G2,B2; ColorBgra CurrentPixel; ColorBgra ClipPixel; m_maxNum = new Surface(src.Size); float DivMultR,DivMultG,DivMultB,DivMultClipR,DivMultClipG,DivMultClipB; int maxR,maxG,maxB,maxClipR,maxClipG,maxClipB; DivMultR = DivMultG = DivMultB = DivMultClipR = DivMultClipG = DivMultClipB = 255f/maxNumber; maxR = maxG = maxB = maxClipR = maxClipG = maxClipB = maxNumber; R1 = G1 = B1 = R2 = G2 = B2 = 255; if (m_clip == null) { m_clip = new Surface(src.Size); } if (!readClipboard && ClipboardMode) { readClipboard = true; clipboardSurface = Services.GetService<IClipboardService>().TryGetSurface(); } for (int y = 0; y < m_clip.Size.Height; y++) { if (IsCancelRequested) return; for (int x = 0; x < m_clip.Size.Width; x++) { CurrentPixel = src[x, y]; int R = CurrentPixel.R; int G = CurrentPixel.G; int B = CurrentPixel.B; if (readClipboard){ if (clipboardSurface != null) { m_clip[x,y] = clipboardSurface.GetBilinearSampleWrapped(x, y); } else { m_clip[x,y] = Color.Transparent; } ClipPixel=m_clip[x,y]; maxClipR = ClipPixel.R > 0 ? ClipPixel.R : 1; maxClipG = ClipPixel.G > 0 ? ClipPixel.G : 1; maxClipB = ClipPixel.B > 0 ? ClipPixel.B : 1; DivMultClipR = 255f / maxClipR; DivMultClipG = 255f / maxClipG; DivMultClipB = 255f / maxClipB; } switch (moduloMode) { case ModuloMode.Modulo: R1 = (byte)(R % (maxR + 1)); G1 = (byte)(G % (maxG + 1)); B1 = (byte)(B % (maxB + 1)); R2 = (byte)(R % (maxClipR + 1)); G2 = (byte)(G % (maxClipG + 1)); B2 = (byte)(B % (maxClipB + 1)); break; case ModuloMode.ModuloContinuous: int TR1 = R / (maxR + 1); int TG1 = G / (maxG + 1); int TB1 = B / (maxB + 1); R1 = (TR1 % 2 == 1) ? (byte)(maxNumber - (R % (maxR + 1))) : (byte)(R % (maxR + 1)); G1 = (TG1 % 2 == 1) ? (byte)(maxNumber - (G % (maxG + 1))) : (byte)(G % (maxG + 1)); B1 = (TB1 % 2 == 1) ? (byte)(maxNumber - (B % (maxB + 1))) : (byte)(B % (maxB + 1)); int TR2 = R / (maxClipR + 1); int TG2 = G / (maxClipG + 1); int TB2 = B / (maxClipB + 1); R2 = (TR2 % 2 == 1) ? (byte)(maxClipR - (R % (maxClipR + 1))) : (byte)(R % (maxClipR + 1)); G2 = (TG2 % 2 == 1) ? (byte)(maxClipG - (G % (maxClipG + 1))) : (byte)(G % (maxClipG + 1)); B2 = (TB2 % 2 == 1) ? (byte)(maxClipB - (B % (maxClipB + 1))) : (byte)(B % (maxClipB + 1)); break; case ModuloMode.DivisiveModulo: if (maxR != 1) { R1 = (byte)(R * DivMultR);} if (maxG != 1) { G1 = (byte)(G * DivMultG);} if (maxB != 1) { B1 = (byte)(B * DivMultB);} if (maxClipR != 1) { R2 = (byte)(R * DivMultClipR);} if (maxClipG != 1) { G2 = (byte)(G * DivMultClipG);} if (maxClipB != 1) { B2 = (byte)(B * DivMultClipB);} break; case ModuloMode.DivisiveModuloContinuous: if (maxR != 1){ float MR1 = R * DivMultR; int CR21 = (int)(MR1 / 256); R1 = (CR21 % 2 == 0) ? (int)(MR1) % 256 : 255 - ((int)(MR1) % 256);} if (maxG != 1){ float MG1 = G * DivMultG; int CG21 = (int)(MG1 / 256); G1 = (CG21 % 2 == 0) ? (int)(MG1) % 256 : 255 - ((int)(MG1) % 256);} if (maxB != 1){ float MB1 = B * DivMultB; int CB21 = (int)(MB1 / 256); B1 = (CB21 % 2 == 0) ? (int)(MB1) % 256 : 255 - ((int)(MB1) % 256);} if (maxClipR != 1){ float MR2 = R * DivMultClipR; int CR22 = (int)(MR2 / 256); R2 = (CR22 % 2 == 0) ? (int)(MR2) % 256 : 255 - ((int)(MR2) % 256);} if (maxClipG != 1){ float MG2 = G * DivMultClipG; int CG22 = (int)(MG2 / 256); G2 = (CG22 % 2 == 0) ? (int)(MG2) % 256 : 255 - ((int)(MG2) % 256);} if (maxClipB != 1){ float MB2 = B * DivMultClipB; int CB22 = (int)(MB2 / 256); B2 = (CB22 % 2 == 0) ? (int)(MB2) % 256 : 255 - ((int)(MB2) % 256);} break; case ModuloMode.ModuloAddition: R1 = (byte)((R + maxR) % 256); G1 = (byte)((G + maxG) % 256); B1 = (byte)((B + maxB) % 256); R2 = (byte)((R + maxClipR) % 256); G2 = (byte)((G + maxClipG) % 256); B2 = (byte)((B + maxClipB) % 256); break; case ModuloMode.ModuloAdditionContinuous: R1 = ((R + maxR) > 255) ? (int)(255 - (R + maxR) % 256) : R + maxR; G1 = ((G + maxG) > 255) ? (int)(255 - (G + maxG) % 256) : G + maxG; B1 = ((B + maxB) > 255) ? (int)(255 - (B + maxB) % 256) : B + maxB; R2 = ((R + maxClipR) > 255) ? (int)(255 - (R + maxClipR) % 256) : R + maxClipR; G2 = ((G + maxClipG) > 255) ? (int)(255 - (G + maxClipG) % 256) : G + maxClipG; B2 = ((B + maxClipB) > 255) ? (int)(255 - (B + maxClipB) % 256) : B + maxClipB; break; } if(Negate){ R1 = 255 - R1; G1 = 255 - G1; B1 = 255 - B1; R2 = 255 - R2; G2 = 255 - G2; B2 = 255 - B2; } m_maxNum[x,y] = ColorBgra.FromBgraClamped(B1, G1, R1, CurrentPixel.A); m_clip[x,y] = ColorBgra.FromBgraClamped(B2, G2, R2, CurrentPixel.A); } } } void Render(Surface dst, Surface src, Rectangle rect) { ColorBgra CurrentPixel; // Step through each row of the current rectangle for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; // Step through each pixel on the current row of the rectangle for (int x = rect.Left; x < rect.Right; x++) { ColorBgra m_maxPixel = m_maxNum[x,y]; ColorBgra m_clipPixel = m_clip[x,y]; if (ClipboardMode){CurrentPixel = m_clipPixel;} else {CurrentPixel = m_maxPixel;} dst[x,y] = CurrentPixel; } } } enum ModuloMode { Modulo, ModuloContinuous, DivisiveModulo, DivisiveModuloContinuous, ModuloAddition, ModuloAdditionContinuous } G'MIC-QT Spoiler #@cli rep_modo_mc: eq. to 'rep_modular_operation_multiple_channels' : (+) rep_modo_mc: rep_modular_operation_multiple_channels $* #@cli rep_modular_operation_multiple_channels: operation,max_channel_value,channel_value(%)...operation_n,max_channel_value_n,channel_value_n #@cli : Apply modular operation for every 2 layers, and for each channels. Either by blending or applying modf function to every 2 layer per channels. #@cli : (eq. to 'rep_modo_mc').\n #@cli : If there is only one set of rep_modo variables,max_channel_value,channel_value, then the values applied here will be applied to the rest of the channels per layers. #@cli : If there is more than one set, then values will be applied with periodic condition. #@cli : If channel_value is less than 0 and greater than or equal to -1, then rep_modular_operation function will use layer blending techniques for 2 layers for every 2 layers. If channel value is less than -1, then operation is disabled on that channel (Only applicable with more than one set of rep_modo variables, and one more layer.).\n #@cli : Note: You can actually assign cmyk mode with this filter by typing 'u cmyk' before 'rep_modo_mc' as the filter will detect if using cmyk instead.\n #@cli : See 'gmic h rep_modf' for more details on variables.\n #@cli : Author: Reptorian. rep_modular_operation_multiple_channels: cmyk=0 if '${}'=='cmyk' cmyk=1 fi tcr={$cmyk?4:3} total_set_of_operation={narg($*)/3} if $total_set_of_operation!=int($total_set_of_operation) error narg("$*")/3==F fi oper_cond={max(0,$total_set_of_operation-2)} if $oper_cond {$oper_cond+1},1,1,3,"begin(argset=[${1--1}]);argset[3*x+c];" s. c oper_set={crop(#-3)} maxchanval_set={crop(#-2)} perc_set={crop(#-1)} rm[-3--1] else oper_set=$1 maxchanval_set=$2 perc_set=$3 fi if $total_set_of_operation>1 nset={$total_set_of_operation-1} else nset=1 fi if $!==1 if s==2||s>$tcr ss={s-1} t_color_oper_set={vector$nset($oper_set)} t_color_maxchanval_set={vector$nset($maxchanval_set)} t_color_perc_set={vector$nset($perc_set)} color_oper=[{vector$tcr($t_color_oper_set)}] color_maxchanval=[{vector$tcr($t_color_maxchanval_set)}] color_perc=[{vector$tcr($t_color_perc_set)}] repeat $ss sh. $> if ($color_perc)[$>]>=0 modf. {($color_oper)[$>]},{($color_maxchanval)[$>]},{abs(($color_perc)[$>])} fi rm. done if $-1>=0 sh. $ss modf. $-3,$-2,$-1 rm. fi else color_oper=[{vectors($oper_set)}] color_maxchanval=[{vectors($maxchanval_set)}] color_perc=[{vectors($perc_set)}] repeat s sh. $> if ($color_perc)[$>]>=0 modf. {($color_oper)[$>]},{($color_maxchanval)[$>]},{abs(($color_perc)[$>])} fi rm. done fi else if min($perc_set)>=0&&$-1>=0 repeat $! l[$>] if s==2||s>$tcr ss={s-1} t_color_oper_set={vector$nset($oper_set)} t_color_maxchanval_set={vector$nset($maxchanval_set)} t_color_perc_set={vector$nset($perc_set)} color_oper=[{vector$tcr($t_color_oper_set)}] color_maxchanval=[{vector$tcr($t_color_maxchanval_set)}] color_perc=[{vector$tcr($t_color_perc_set)}] else ss={s} color_oper=[{vectors($oper_set)}] color_maxchanval=[{vectors($maxchanval_set)}] color_perc=[{vectors($perc_set)}] fi repeat $ss sh. $> if ($color_perc)[$>]>=0 modf. {($color_oper)[$>]},{($color_maxchanval)[$>]},{abs(($color_perc)[$>])} fi rm. done if s==2||s>$tcr sh. {s-1} modf. ${-3--1} rm. fi endl done else repeat int($!/2) l[{$>*2},{$>*2+1}] loc_a={$>*2} loc_b={$>*2+1} if s#0!=s#1 error (s#0#$loc_a!=s#1#$loc_b)==F fi if s==2||s>$tcr ss={s-1} t_color_oper_set={vector$nset($oper_set)} t_color_maxchanval_set={vector$nset($maxchanval_set)} t_color_perc_set={vector$nset($perc_set)} color_oper=[{vector$tcr($t_color_oper_set)}] color_maxchanval=[{vector$tcr($t_color_maxchanval_set)}] color_perc=[{vector$tcr($t_color_perc_set)}] else ss={s} color_oper=[{vectors($oper_set)}] color_maxchanval=[{vectors($maxchanval_set)}] color_perc=[{vectors($perc_set)}] fi repeat $ss if ($color_perc)[$>]>=-1 sh[0] $> sh[1] $> rep_modo[-2,-1] {($color_oper)[$>]},{($color_maxchanval)[$>]},{($color_perc)[$>]} rm[-2,-1] fi done if ($-1>=-1)&&(s==2||s>$tcr) v + echo pass v - sh[0] {s#0-1} sh[1] {s#0-1} rep_modo[-2,-1] ${-3--1} rm[-2,-1] fi endl done fi fi #@cli rep_modo: eq. to 'rep_modular_operation'. : (+) rep_modo: rep_modular_operation $* #@cli rep_modular_operation: operation,max_channel_value,channel_value(%) #@cli : Apply modular operation to every 2 layers. Either by blending layers or applying modf function to every 2 layers. #@cli : (eq. to 'rep_modo').\n #@cli : If channel_value is less than 0, then rep_modular_operation function will use layer blending techniques for 2 layers for every 2 layers. #@cli : See 'gmic h rep_modf' for more details.\n #@cli : Author: Reptorian. rep_modular_operation:rv={int($!/2)} if $!>1&&$3<0 repeat $rv l[{$>*2},{$>*2+1}] +modf[-1] $1,$2,[-2] modf[0] $1,$2,[1] rm.. endl done else if $!%2 if $!>2 modf[^-1] $1,$2,$3 else modf $1,$2,$3 fi else modf $1,$2,$3 fi fi #@cli modf: eq. to 'modular_formula'. : (+) modf: if ${is_image_arg\ $3} pass$3 0 modular_formula $1,$2,[-1] rm. else modular_formula ${1-3} fi #@cli modular_formula : operation,max_channel_value,channel_value(%) : operation,max_channel_value,[image] #@cli : Apply modular formulas into selected images. 'channel_value' can be values outside the channel ranges of image. #@cli : (eq. to 'modf').\n #@cli : operation can be { 0=modulo | 1=modulo continuous | 2=divisive | 3=divisive continuous | 4=additive | 5=additive continuous} #@cli : Author: Reptorian. modular_formula: if ${is_image_arg\ $3} arg_img=-2 e[] "Apply modular formulas using image as reference for variable value." else arg_img=-1 e[] "Apply modular formulas using {$3*abs($2)} as variable value. " fi if $1<0||$1>5 error ""$"1<6||"$"1>=0 => F" fi if $1!=int($1) error ""$"1!=INT" fi if $arg_img==-2 pass$3 1 fi f[0-{$arg_img}] "begin(eps=10^-8;image=1;skip=1;); if(image, if("$arg_img"==-2 ,var3_mod=i#-1/abs($2); ,var3_mod=$3;image-=1; ); if(!var3_mod,var3_mod=eps); maxnum=$1<2?var3_mod*abs($2)+eps:abs($2)+eps; var3_mod=var3_mod*abs($2); mf(a)=a-maxnum*floor(a/maxnum); amf(a)=(if(floor(a/maxnum)%2,(maxnum-eps)-mf(a),mf(a))); ); if(skip,skip-=1; if($1>3, if(!($1%2) ,calc(a)=mf(a+var3_mod); ,calc(a)=amf(a+var3_mod); ); ,if($1>1, if(!($1%2) ,calc(a)=mf(a*(abs($2)/var3_mod)); ,calc(a)=amf(a*(abs($2)/var3_mod)); ); ,if(!($1%2) ,calc(a)=mf(a); ,calc(a)=amf(a); ); ); ); ); calc(i); end(if(!image, maxnum=maxnum; var3_mod=var3_mod; ); if(!skip; if($1>3, if(!($1%2) ,calc(a)=mf(a+var3_mod); ,calc(a)=amf(a+var3_mod); ); ,if($1>1, if(!($1%2) ,calc(a)=mf(a*(abs($2)/var3_mod)); ,calc(a)=amf(a*(abs($2)/var3_mod)); ); ,if(!($1%2) ,calc(a)=mf(a); ,calc(a)=amf(a); ); ); ); ); ); " replace_nan 0 if $arg_img==-2 rm. fi #@gui Modulos Operation:fx_rep_modo,fx_rep_modo_preview #@gui :_=note("<b>Initial</b>") #@gui :Colour Space=choice(0,"RGB","sRGB","RYB","CMY","CMYK","HCY","HSI","HSL","HSV","LAB","LCH","YIQ","YUV","YCbCr","YCbCrGLIC","XYZ","YES","Kodak 1","Ohta") #@gui :Edit Multiple Channels at once?=bool(0) #@gui :Reverse Layers?=bool(0) #@gui :_=separator(),_=note("<b>Operation</b>") #@gui :Channel Set=choice(0,"Color Channels","Alpha") #@gui :Channel=choice(0,"First","Second","Third") #@gui :Channel=choice(0,"First","Second","Third","Fourth") #@gui :Channel=choice(0,"First","Second","Third","Fourth","Fifth") #@gui :Operation=choice(3,"Modulo","Modulo - Continuous","Divisive Modulo","Divisive Modulo - Continuous","Additive Modulo","Additive Modulo Continuous") #@gui :Factor (%)=float(100,0,100) #@gui :Use Layer as Factor instead?=bool(0) #@gui :Negate?=bool(0) #@gui :Operation=choice(3,"Modulo","Modulo - Continuous","Divisive Modulo","Divisive Modulo - Continuous","Additive Modulo","Additive Modulo Continuous") #@gui :Factor (%)=float(100,0,100) #@gui :Use Layer as Factor instead?=bool(0) #@gui :Negate?=bool(0) #@gui :Disable Effect for Channel #1=bool(0) #@gui :Operation=choice(3,"Modulo","Modulo - Continuous","Divisive Modulo","Divisive Modulo - Continuous","Additive Modulo","Additive Modulo Continuous") #@gui :Factor (%)=float(100,0,100) #@gui :Use Layer as Factor instead?=bool(0) #@gui :Negate?=bool(0) #@gui :Disable Effect for Channel #2=bool(0) #@gui :Operation=choice(3,"Modulo","Modulo - Continuous","Divisive Modulo","Divisive Modulo - Continuous","Additive Modulo","Additive Modulo Continuous") #@gui :Factor (%)=float(100,0,100) #@gui :Use Layer as Factor instead?=bool(0) #@gui :Negate?=bool(0) #@gui :Disable Effect for Channel #3=bool(0) #@gui :Operation=choice(3,"Modulo","Modulo - Continuous","Divisive Modulo","Divisive Modulo - Continuous","Additive Modulo","Additive Modulo Continuous") #@gui :Factor (%)=float(100,0,100) #@gui :Use Layer as Factor instead?=bool(0) #@gui :Negate?=bool(0) #@gui :Disable Effect for Channel #4=bool(0) #@gui :Operation=choice(3,"Modulo","Modulo - Continuous","Divisive Modulo","Divisive Modulo - Continuous","Additive Modulo","Additive Modulo Continuous") #@gui :Factor (%)=float(100,0,100) #@gui :Use Layer as Factor instead?=bool(0) #@gui :Negate Alpha?=bool(0) #@gui :Disable Effect for Alpha=bool(1) #@gui :Disable Effect for Colour Channel #1=bool(0) #@gui :Disable Effect for Colour Channel #2=bool(0) #@gui :Disable Effect for Colour Channel #3=bool(0) #@gui :Disable Effect for Colour Channel #4=bool(0) #@gui :Disable Effect for Alpha Channel?=bool(1) #@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 #@gui :_=separator(), _=note("<small>Author: Reptorian. Latest Update: <i>2020/10/14</i>.</small>") fx_rep_modo: if ($1>=0&&$1<4)||$1>=9 color_id=[{vector3(255)}] elif $1==4 color_id=[{vector4(255)}] elif $1<9 color_id=[360,1,1] fi if $1==4 v_n={$2?(!$37&&$11):(!$16&&$15)},{$2?(!$38&&$11):(!$21&&$20)},{$2?(!$39&&$11):(!$26&&$25)},{$2?(!$40&&$11):(!$31&&$30)},{$2?(!$41&&$11):(!$36&&$35)} else v_n={$2?(!$37&&$11):(!$16&&$15)},{$2?(!$38&&$11):(!$21&&$20)},{$2?(!$39&&$11):(!$26&&$25)},{$2?(!$41&&$11):(!$36&&$35)} fi use_negate=max($v_n) v_n=[$v_n] color_channels={$1==4?4:3} convert_colors_fwd=${arg\ $1+1,,rgb2srgb,rgb2ryb,rgb2cmy,,rgb2hcy,rgb2hsi,rgb2hsl,rgb2hsv,rgb2lab8,rgb2lch8,rgb2yiq8,rgb2yuv8,rgb2ycbcr,rgb2ycbcrglic,rgb2xyz8,rgb2yes8,rgb2k18,rgb2ohta8} convert_colors_bwd=${arg\ $1+1,,srgb2rgb,ryb2rgb,cmy2rgb,,hcy2rgb,hsi2rgb,hsl2rgb,hsv2rgb,lab82rgb,lch82rgb,yiq82rgb,yuv82rgb,ycbcr2rgb,ycbcrglic2rgb,xyz82rgb,yes82rgb,k182rgb,ohta82rgb} if $1 repeat $! l[$>] if $1!=4 sh. 0,2 $convert_colors_fwd. rm. else if s==3 rgb2cmyk elif s==4 s c,-3 rgb2cmyk.. a c fi u cmyk fi endl done fi if $color_channels==3 modo_variables={$2?$8:$12},{($color_id)[0]},{$2?($37?-2:($10?-1:$9%)):($16?-2:($14?-1:$13%))},{$2?$8:$17},{($color_id)[1]},{$2?($38?-2:($10?-1:$9%)):($21?-2:($19?-1:$18%))},{$2?$8:$22},{($color_id)[2]},{$2?($39?-2:($10?-1:$9%)):($26?-2:($24?-1:$23%))},$32,255,{($2?$41:$36)?-2:($34?-1:$33%)} else modo_variables={$2?$8:$12},{($color_id)[0]},{$2?($37?-2:($10?-1:$9%)):($16?-2:($14?-1:$13%))},{$2?$8:$17},{($color_id)[1]},{$2?($38?-2:($10?-1:$9%)):($21?-2:($19?-1:$18%))},{$2?$8:$22},{($color_id)[2]},{$2?($39?-2:($10?-1:$9%)):($26?-2:($24?-1:$23%))},{$2?$8:$27},{($color_id)[3]},{$2?($40?-2:($10?-1:$9%)):($30?-2:($29?-1:$28%))},$32,255,{($2?$41:$36)?-2:($34?-1:$33%)} fi rep_modo_mc $modo_variables if $use_negate repeat $! l[$>] ss={s-1} repeat s if $>!=$ss if ($v_n)[$>] sh. $> f. ($color_id)[$>]-i rm. fi else if ($v_n)[$>] sh. $> f. 255-i rm. fi fi done endl done fi if $1 repeat $! l[$>] if $1!=4 sh. 0,2 $convert_colors_bwd. rm. else if s==4 cmyk2rgb elif s==5 s c,-4 cmyk2rgb.. a c fi fi endl done fi if !$3 rv fi if '$_host'=='paintdotnet' k[0] fi fx_rep_modo_preview: two_plus_layer={$!>1} ms=${-max_s} rv gui_split_preview "fx_rep_modo ${1-41}",${-3--1} contain_alpha={$ms>3} activate_individual_channels={!$2?2} mode_0={$contain_alpha&&$2?2} mode_1={!$contain_alpha&&!$2?2} mode_2={$1!=4?(($contain_alpha&&!$2)?2):((!$contain_alpha&&!$2)?2)} mode_3={!$2?(($1==4&&$contain_alpha)?2)} use_channel_1_a={$5==0?2} use_channel_1_b={$6==0?2} use_channel_1_c={$7==0?2} use_channel_2_a={$5==1?2} use_channel_2_b={$6==1?2} use_channel_2_c={$7==1?2} use_channel_3_a={$5==2?2} use_channel_3_b={$6==2?2} use_channel_3_c={$7==2?2} activate_a={!$2?(($mode_1?$use_channel_1_a:($mode_2?$use_channel_1_b:$use_channel_1_c))?2)} activate_b={($mode_1?$use_channel_2_a:($mode_2?$use_channel_2_b:$use_channel_2_c))?2} activate_c={($mode_1?$use_channel_3_a:($mode_2?$use_channel_3_b:$use_channel_3_c))?2} activate_d={$1==4?($mode_2?($6==3?2):($mode_3?($7==3?2)))} activate_e={$2?($mode_0?($4==1?2)):($contain_alpha?($1!=4?($mode_2?($6==3?2):($7==4?2)):($mode_3?$7==4?2)))} activate_csm={$2&&!$4?2} activate_bottom_sec={$2?2} u "{$1}"\ "{$2}"\ "{$3}"\ "{$4}_"{$mode_0}\ "{$5}_"{$mode_1}\ "{$6}_"{$mode_2}\ "{$7}_"{$mode_3}\ "{$8}_"{$activate_csm}\ "{$9}_"{$activate_csm}\ "{$10}_"{$two_plus_layer?$activate_csm}\ "{$11}_"{$activate_csm}\ "{$12}_"{$activate_a}\ "{$13}_"{$activate_a}\ "{$14}_"{$two_plus_layer?$activate_a}\ "{$15}_"{$activate_a}\ "{$16}_"{$activate_a}\ "{$17}_"{$activate_b}\ "{$18}_"{$activate_b}\ "{$19}_"{$two_plus_layer?$activate_b}\ "{$20}_"{$activate_b}\ "{$21}_"{$activate_b}\ "{$22}_"{$activate_c}\ "{$23}_"{$activate_c}\ "{$24}_"{$two_plus_layer?$activate_c}\ "{$25}_"{$activate_c}\ "{$26}_"{$activate_c}\ "{$27}_"{$activate_d}\ "{$28}_"{$activate_d}\ "{$29}_"{$two_plus_layer?$activate_d}\ "{$30}_"{$activate_d}\ "{$31}_"{$activate_d}\ "{$32}_"{$activate_e}\ "{$33}_"{$activate_e}\ "{$34}_"{$two_plus_layer?$activate_e}\ "{$35}_"{$activate_e}\ "{$36}_"{!$2?$activate_e}\ "{$37}_"{$activate_bottom_sec}\ "{$38}_"{$activate_bottom_sec}\ "{$39}_"{$activate_bottom_sec}\ "{$40}_"{$2?($1==4?2)}\ "{$41}_"{($2&&$contain_alpha)?2}\ "{$42}"\ "{$43,$44}" EDIT: @toe_head2001 has provided cleaner code of the current plugin. So I inserted it in here for quicker access. EDIT: Added new features in 10/09/2020 EDIT: Added G'MIC-QT source code to the g'mic-qt filter, and a special note for feature requests. Edited October 14, 2020 by Reptillian Update post 1 1 Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me. Link to comment Share on other sites More sharing options...
HyReZ Posted December 9, 2019 Share Posted December 9, 2019 (edited) Thanks for the Modulo plugin Toolkit! I have tested it with gray scale and full 24 bit color image, and a few in between. I love the Adjustment Effect! Before I was using the Metalize Effect to achieve what I needed, but your Adjustment appears to have greater variation yet it is simple to use. Edited December 9, 2019 by HyReZ Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted December 9, 2019 Share Posted December 9, 2019 If you're interested in some feedback for your C# code, I've made some cleanups to your code. Hopefully you'll learn something new. Spoiler // Name: Image Modulo Toolkit // Submenu: Adjustment // Author: Reptorian // Title: Image Modulo Toolkit // Version: 1 // Desc: Adjust image values based on I%(Amount+1) // Keywords: Modulo // URL: // Help: #region UICode ListBoxControl<ModuloMode> moduloMode = ModuloMode.Modulo; // Mode | Modulo | Modulo Continuous | Divisive Modulo | Divisive Modulo Continuous | Modulo Addition | Modulo Addition Continuous IntSliderControl maxNumber = 255; // [1,255] Maximum Number #endregion void Render(Surface dst, Surface src, Rectangle rect) { ColorBgra CurrentPixel; float DivMult = 255f / maxNumber; for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { CurrentPixel = src[x, y]; int R = CurrentPixel.R; int G = CurrentPixel.G; int B = CurrentPixel.B; switch (moduloMode) { case ModuloMode.Modulo: R = (byte)(R % (maxNumber + 1)); G = (byte)(G % (maxNumber + 1)); B = (byte)(B % (maxNumber + 1)); break; case ModuloMode.ModuloContinuous: int TR = R / (maxNumber + 1); int TG = G / (maxNumber + 1); int TB = B / (maxNumber + 1); R = (TR % 2 == 1) ? (byte)(maxNumber - (R % (maxNumber + 1))) : (byte)(R % (maxNumber + 1)); G = (TG % 2 == 1) ? (byte)(maxNumber - (G % (maxNumber + 1))) : (byte)(G % (maxNumber + 1)); B = (TB % 2 == 1) ? (byte)(maxNumber - (B % (maxNumber + 1))) : (byte)(R % (maxNumber + 1)); break; case ModuloMode.DivisiveModulo: if (maxNumber != 1) { R = (byte)(R * DivMult); G = (byte)(G * DivMult); B = (byte)(B * DivMult); } break; case ModuloMode.DivisiveModuloContinuous: if (maxNumber != 1) { float MR = R * DivMult; float MG = G * DivMult; float MB = B * DivMult; int CR2 = (int)(MR / 256); int CG2 = (int)(MG / 256); int CB2 = (int)(MB / 256); R = (CR2 % 2 == 0) ? (int)(MR) % 256 : 255 - ((int)(MR) % 256); G = (CG2 % 2 == 0) ? (int)(MG) % 256 : 255 - ((int)(MG) % 256); B = (CB2 % 2 == 0) ? (int)(MB) % 256 : 255 - ((int)(MB) % 256); } break; case ModuloMode.ModuloAddition: R = (byte)((R + maxNumber) % 256); G = (byte)((G + maxNumber) % 256); B = (byte)((B + maxNumber) % 256); break; case ModuloMode.ModuloAdditionContinuous: R = ((R + maxNumber) > 255) ? (int)(255 - (R + maxNumber) % 256) : R + maxNumber; G = ((G + maxNumber) > 255) ? (int)(255 - (G + maxNumber) % 256) : G + maxNumber; B = ((B + maxNumber) > 255) ? (int)(255 - (B + maxNumber) % 256) : B + maxNumber; break; } dst[x, y] = ColorBgra.FromBgraClamped(B, G, R, CurrentPixel.A); } } } enum ModuloMode { Modulo, ModuloContinuous, DivisiveModulo, DivisiveModuloContinuous, ModuloAddition, ModuloAdditionContinuous } 2 Quote (September 25th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
Reptillian Posted December 9, 2019 Author Share Posted December 9, 2019 28 minutes ago, toe_head2001 said: If you're interested in some feedback for your C# code, I've made some cleanups to your code. Hopefully you'll learn something new. Reveal hidden contents // Name: Image Modulo Toolkit // Submenu: Adjustment // Author: Reptorian // Title: Image Modulo Toolkit // Version: 1 // Desc: Adjust image values based on I%(Amount+1) // Keywords: Modulo // URL: // Help: #region UICode ListBoxControl<ModuloMode> moduloMode = ModuloMode.Modulo; // Mode | Modulo | Modulo Continuous | Divisive Modulo | Divisive Modulo Continuous | Modulo Addition | Modulo Addition Continuous IntSliderControl maxNumber = 255; // [1,255] Maximum Number #endregion void Render(Surface dst, Surface src, Rectangle rect) { ColorBgra CurrentPixel; float DivMult = 255f / maxNumber; for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { CurrentPixel = src[x, y]; int R = CurrentPixel.R; int G = CurrentPixel.G; int B = CurrentPixel.B; switch (moduloMode) { case ModuloMode.Modulo: R = (byte)(R % (maxNumber + 1)); G = (byte)(G % (maxNumber + 1)); B = (byte)(B % (maxNumber + 1)); break; case ModuloMode.ModuloContinuous: int TR = R / (maxNumber + 1); int TG = G / (maxNumber + 1); int TB = B / (maxNumber + 1); R = (TR % 2 == 1) ? (byte)(maxNumber - (R % (maxNumber + 1))) : (byte)(R % (maxNumber + 1)); G = (TG % 2 == 1) ? (byte)(maxNumber - (G % (maxNumber + 1))) : (byte)(G % (maxNumber + 1)); B = (TB % 2 == 1) ? (byte)(maxNumber - (B % (maxNumber + 1))) : (byte)(R % (maxNumber + 1)); break; case ModuloMode.DivisiveModulo: if (maxNumber != 1) { R = (byte)(R * DivMult); G = (byte)(G * DivMult); B = (byte)(B * DivMult); } break; case ModuloMode.DivisiveModuloContinuous: if (maxNumber != 1) { float MR = R * DivMult; float MG = (float)(G * DivMult); float MB = (float)(B * DivMult); int CR2 = (int)(MR / 256); int CG2 = (int)(MG / 256); int CB2 = (int)(MB / 256); R = (CR2 % 2 == 0) ? (int)(MR) % 256 : 255 - ((int)(MR) % 256); G = (CG2 % 2 == 0) ? (int)(MG) % 256 : 255 - ((int)(MG) % 256); B = (CB2 % 2 == 0) ? (int)(MB) % 256 : 255 - ((int)(MB) % 256); } break; case ModuloMode.ModuloAddition: R = (byte)((R + maxNumber) % 256); G = (byte)((G + maxNumber) % 256); B = (byte)((B + maxNumber) % 256); break; case ModuloMode.ModuloAdditionContinuous: R = ((R + maxNumber) > 255) ? (int)(255 - (R + maxNumber) % 256) : R + maxNumber; G = ((G + maxNumber) > 255) ? (int)(255 - (G + maxNumber) % 256) : G + maxNumber; B = ((B + maxNumber) > 255) ? (int)(255 - (B + maxNumber) % 256) : B + maxNumber; break; } dst[x, y] = ColorBgra.FromBgraClamped(B, G, R, CurrentPixel.A); } } } enum ModuloMode { Modulo, ModuloContinuous, DivisiveModulo, DivisiveModuloContinuous, ModuloAddition, ModuloAdditionContinuous } This is just once in a while thing I just did. Any changes as in cleanup or new features in codes, I'll be putting it in the first post and the first post can be edited if I haven't. I don't plan to work on it anymore. Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me. Link to comment Share on other sites More sharing options...
Reptillian Posted December 10, 2019 Author Share Posted December 10, 2019 6 hours ago, welshblue said: It definitely helps to speed things up on a few techniques. (post image is down so I can't post a result) Possibly tell people where to find it ? I checked all sub menus before looking at the source code and realising it was in Adjustments On the question, it's done. What other uses you found other than gradient map preparation or glitch art? Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me. Link to comment Share on other sites More sharing options...
Reptillian Posted December 11, 2019 Author Share Posted December 11, 2019 (edited) I'm thinking of a better name. Is 'Modulus Operation' is a better name or is 'Modular Formula' better for this plugin. The second one tells what it does better than the first in my opinion. Edited December 11, 2019 by Reptillian Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me. Link to comment Share on other sites More sharing options...
HyReZ Posted December 11, 2019 Share Posted December 11, 2019 On 12/10/2019 at 2:54 AM, welshblue said: I checked all sub menus before looking at the source code and realizing it was in Adjustments Before I added my comment above, I had to use the Plugin Browser to find where this plugin resided. There have been a few times where the creator of a plugin failed to include information about where the plugin could be found. I see that Reptillian has corrected this omission. Quote Link to comment Share on other sites More sharing options...
lynxster4 Posted December 11, 2019 Share Posted December 11, 2019 That text looks super-clean @welshblue! 😊 I just love text-effects! 1 Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to comment Share on other sites More sharing options...
Reptillian Posted February 9, 2020 Author Share Posted February 9, 2020 (edited) First post edited, ditched mediafire and uploaded directly to this site. Now you won't have to get bombarded by ads just to download. Edited February 9, 2020 by Reptillian Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me. Link to comment Share on other sites More sharing options...
Reptillian Posted October 10, 2020 Author Share Posted October 10, 2020 Added new features! Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me. Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.