Jump to content

Recommended Posts

This is a distortion plugin that can be found under 'effect/distort'. What this does is shift pixels to boundary with the option to set direction, influence level, threshold level, and position.

 

Note: There is two difficult to fix bug. If someone wants to try fixing it, then you're more than welcome to, but please share the changes if you do.

 

1. Transparent dots appears with some settings.

 

2. Very rarely, the plugin crash. Wait for the render to finish before changing settings.

----------------------------------

Here's the test image which is a strange attractor. (IMGUR doesn't support alpha)

 

qx9mKr0.png

 

With setting on position -53% ; Influence - 71% ; Threshold - 70 ; Axis to Vertical.

 

fpzDrUs.png


And of course, the obligatory interface picture

 

pJaT6Mk.png

 

To download this plugin -> Shifted Group Pixel to Boundary.dll

 

----------------------------------

License : CeCiLL v2.0 - https://cecill.info/licences/Licence_CeCILL_V2-en.html

 

Codelab Source code

 

// Name: Axis-Based Shift Grouped Pixel to Boundary
// Submenu: Effects / Distortion
// Author: Reptorian
// Title: Axis-Based Shift Grouped Pixel to Boundary
// Version: 0.7
// Desc: Converted from G'MIC-QT rep_sptbwgp cli filter which is also created by Reptorian.
// Keywords: Gravity
// URL: https://forums.getpaint.net/profile/85868-reptillian/
// Help:
#region UICode
DoubleSliderControl positionperc = -100; // [-100,100] Position of Pixels (%)
DoubleSliderControl influenceperc = 100; // [0,100] Influence Factor (%)
IntSliderControl alpha_threshold = 255; // [1,255] Alpha Threshold
ListBoxControl axis = 1; // Axis|Horizontal|Vertical
#endregion

int[] rowNonZeroAlphas = null;
int[] columnNonZeroAlphas = null;
ColorBgra[,] altsrf = null;

void PreRender(Surface dst, Surface src)
{
    int w=src.Width,h=src.Height;
    columnNonZeroAlphas = new int[w];rowNonZeroAlphas = new int[h];
    altsrf = new ColorBgra[w,h];
    int non_alpha_count = 0;
    int tx,ty,nx,ny,fx,fy,N;
    double tny,tnx;
    
    double position = (positionperc / 100 + 1) / 2;
    double influence_factor = influenceperc / 100;
    double invert_factor = 1 - influence_factor;
    
    if (axis==1)
    {
        for (int x = 0 ; x < w ; x++)
        {
            non_alpha_count = 0 ;            
            for (int y = 0; y < h; y++){if (src[x,y].A >= alpha_threshold){non_alpha_count++;}}
            columnNonZeroAlphas[x] = non_alpha_count ;
        }
        
        for (int x = 0 ; x < w ; x++)
        {
            ny = h - 1;
            if (columnNonZeroAlphas[x] != 0)
            {
                N = columnNonZeroAlphas[x];
                ty = h - N;
                ny-=(int)(Math.Round(ty * position));
                for (int y = h - 1 ; y >= 0 ; y--)
                {
                    if (N != 0)
                    {
                        if (src[x,y].A >= alpha_threshold)
                        {
                            tny = influence_factor * (double)(ny) + invert_factor * (double)(y);
                            
                            if (position == 1)
                            { fy = (int)(Math.Floor(tny)) ; }
                            else
                            { fy = (int)(Math.Ceiling(tny)) ; }
                            
                            N--;
                            altsrf[x,fy] = src[x,y] ;
                            ny--;                            
                        }
                    }
                    else {break;}
                }
            }
        }
    }
    else
    {
        for (int y = 0 ; y < h ; y++)
        {
            non_alpha_count = 0 ;            
            for (int x = 0; x < w; x++){if (src[x,y].A >= alpha_threshold){non_alpha_count++;}}
            rowNonZeroAlphas[y] = non_alpha_count ;
        }
        
        for (int y = 0 ; y < h ; y++)
        {
            nx = 0;
            if (rowNonZeroAlphas[y] != 0)
            {
                N = rowNonZeroAlphas[y];
                tx = w - N;
                nx+=(int)(Math.Round(tx * position));
                for (int x = 0 ; x < w ; x++)
                {
                    if (N != 0)
                    {
                        if (src[x,y].A >= alpha_threshold)
                        {
                            tnx = influence_factor * (double)(nx) + invert_factor * (double)(x);
                            
                            if (position == 1)
                            { fx = (int)(Math.Ceiling(tnx)) ; }
                            else
                            { fx = (int)(Math.Floor(tnx)) ; }
                            
                            N--;
                            altsrf[fx,y] = src[x,y] ;
                            nx++;                            
                        }
                    }
                    else {break;}
                }
            }
        }
    }
}

void Render(Surface dst, Surface src, Rectangle rect)
{
    Rectangle selection = EnvironmentParameters.SelectionBounds;
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
            dst[x,y] = altsrf[x,y] ;
        }
    }
}

 

 

G'MIC-QT rep_sptbwgp source code

 

#@cli rep_sptbwgp: (eq. to rep_shift_pixel_to_boundary_with_group_pixels)
rep_sptbwgp: rep_shift_pixel_to_boundary_with_group_pixels $*
#@cli rep_shift_pixel_to_boundary_with_group_pixels: -1<=_position<=1, _axis={ 0=Horizontal | 1=Vertical }, 0<=_influence_factor<=1, _threshold>=0,_channel_mode
#@cli : Shifts pixels to boundary by percentage using grouped pixels. position less than .5 means shift will be negative, and position greater than .5 means shift will be positive.
#@cli : Assign an argument to _channel_mode if you want to disable restricting effect on alpha channel or avoid manipulating 4 channels image in case of CMYKA image. Only use in rare cases!
#@cli : Default values: '_position=-1','_axis=1','_influence_factor=1','_threshold=0','_channel_mode='
rep_shift_pixel_to_boundary_with_group_pixels:
skip ${1=-1},${2=1},${3=1},${4=0},${5=}
any_channels=0
tcr=3
influence_factor={min(abs($3),1)}
position={(($1+1)/2)}
if $4>0 m "sptbwgp_remove_alpha_threshold : f i>=$4?i"
else    m "sptbwgp_remove_alpha_threshold : f i?i"
fi
if $4>0 m "sptbwgp_filter_nonzero : 100%,100%,100%,1,i(#0,x,y,z,s#-1-1)>=$4?1"
else    m "sptbwgp_filter_nonzero : 100%,100%,100%,1,i(#0,x,y,z,s#-1-1)?1"
fi
if $2 m "sptbwgp_create_strip : {w},1,1,1,sum(crop(#-1,x,0,0,0,1,h#-1,1,1))"
else  m "sptbwgp_create_strip : {h},1,1,1,sum(crop(#-1,0,x,0,0,w#-1,1,1,1))"
fi
if   $position<0 position=0
elif $position>1 position=1
fi
if narg($5)
    if $5>=0
        tcr+=1
    else
        any_channels=1
    fi
fi
if $influence_factor
    repeat $! l[$>]
        if (s==2||s>$tcr)||$any_channels
            tic
            sh {s-1} sptbwgp_remove_alpha_threshold. rm.
            sptbwgp_filter_nonzero.
            sptbwgp_create_strip
            alpinfo={crop(i#-1)}
            rm[-2,-1]
            if $2 100%,100%,100%,100%,begin(alpi=[$alpinfo];);if(alpi[x]==h,I#0);
            else  100%,100%,100%,100%,begin(alpi=[$alpinfo];);if(alpi[y]==w,I#0);
            fi
            eval ${-math_lib}"            
                const influence_factor="$influence_factor";
                const invert_factor=1-influence_factor;
                const position="$position";
                const alp=s-1;
                alpi=["$alpinfo"];
                if($2
                ,
                    if(position==1
                    ,func(a)=ceil(a);
                    ,func(a)=floor(a);
                    );
                ,
                    if(position==1
                    ,func(a)=floor(a);
                    ,func(a)=ceil(a);
                    );
                );
                if($2,
                    for(xx=0,xx<w,xx++,
                        nyy=h-1;
                        if(alpi[xx]&&alpi[xx]<h,
                            N=alpi[xx];
                            tyy=h-N;
                            nyy-=tyy*position;
                            for(yy=h-1,yy>-1,yy--,
                                if(N,
                                    if(i(#0,xx,yy,z,alp),
                                        N--;
                                        tnyy=influence_factor*nyy+invert_factor*yy;
                                        I(#1,xx,func(tnyy))=I(#0,xx,yy);
                                        nyy--;
                                    );
                                    ,break();
                                );
                            );
                        );
                    );
                ,
                    for(yy=0,yy<h,yy++,
                        nxx=0;
                        if(alpi[yy]&&alpi[yy]<w,
                            N=alpi[yy];
                            txx=w-N;
                            nxx+=txx*position;
                            for(xx=0,xx<w,xx++,
                                if(N,
                                    if(i(#0,xx,yy,z,alp),
                                        N--;
                                        tnxx=influence_factor*nxx+invert_factor*xx;
                                        I(#1,func(tnxx),yy)=I(#0,xx,yy);
                                        nxx++;
                                    );
                                    ,break();
                                );
                            );
                        );
                    );
                );
            "
            rm..
            toc
        fi
    endl done
fi
uncommand sptbwgp_filter_nonzero,sptbwgp_create_strip,sptbwgp_remove_alpha_threshold

#@gui Grouped Pixel Axis-Based Shift : fx_rep_sptbwgp,fx_rep_sptbwgp_preview
#@gui : note=note("Based off MadJik's Paint.NET Gravity Plugin. New feature are shift position, and influence factor."),sep=separator()
#@gui : Shift Position (%)=float(0,-100,100)
#@gui : Influence Factor (%)=float(0,0,100)
#@gui : Threshold (%)=float(0,0,100)
#@gui : Axis=choice(0,"Horizontal","Vertical")
#@gui : sep=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 : sep=separator(), note=note("<small>Author: Reptorian. Latest Update: <i>2019/5/14</i>.</small>")
fx_rep_sptbwgp:
position={$1%}
axis=$4
threshold={$3%*255}
influence={$2%}
rep_sptbwgp $position,$axis,$influence,$threshold

Edited by Reptillian
  • Upvote 1
Link to post
Share on other sites
Posted (edited)
4 hours ago, Djisves said:

Can you give details please?

Done. 1st requires a new algorithm that is fast. 2nd is a issue that I can't seem to get around. Both gmic-qt and pdn plugin has this issue though they're rare in both case.

 

I do have a theory on solving the first one though results would be a little different.

Edited by Reptillian
  • Upvote 1
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...