Jump to content

Unfinished plugins


xod

Recommended Posts

Hello @xod ,

 

I have updated to the new version of Custom Corner Frame and I get an error when I try to use it. I did not get this error with the previous version. 

Spoiler

File: C:\Program Files\Paint.NET\Effects\CustomCornerFrame.dll
      Name: CustomCornerFrameEffect.CustomCornerFrameEffectPlugin
      Version: 1.0.1.0
      Author: Copyright ©2020 by xod
      Copyright: Custom Corner Frame
      Website: https://forums.getpaint.net/
      Full error message: System.MissingMethodException: Method not found: 'System.Drawing.Rectangle PaintDotNet.Effects.EffectEnvironmentParameters.get_SelectionBounds()'.
   at CustomCornerFrameEffect.CustomCornerFrameEffectPlugin.OnSetupOptions(OptionContext optContext)
   at OptionBased.Effects.OptionBasedEffect.CreateConfigDialog()
   at PaintDotNet.Menus.EffectMenuBase.RunEffectImpl(Type effectType) in D:\src\pdn\src\PaintDotNet\Menus\EffectMenuBase.cs:line 873
 

 

Edited by Eli
Problem solved when I updated to latest version of Paint.Net :)
Link to comment
Share on other sites

BoltBait explains in the Creative Text Pro v1.0 plugin code:

// For older Paint.NET use this line instead of the next:
// Rectangle selection = EnvironmentParameters.GetSelection(srcBounds).GetBoundsInt();
   Rectangle selection = EnvironmentParameters.SelectionBounds;

So, you did the right thing: Paint.net update.

Link to comment
Share on other sites

  • 3 weeks later...
Link to comment
Share on other sites

  • 4 weeks later...

Hi @xod I have been enjoying the Custom Corner Frame plugin so much that I want it double if possible :) . It must be because I have been locked at home for 10 days already. 

Spoiler

double-corner-frames-572b50a.png

😄

 

  • Like 2
Link to comment
Share on other sites

Link to comment
Share on other sites

  • 1 month later...

I could not get this filter to work, so I decided to dump this in this thread in case anyone wants to finish and is searching for unfinished plugin

 

 

// Name: Axis-Based Shift Grouped Pixel to Boundary
// Submenu: Effects / Distortion
// Author: Reptorian
// Title: Axis-Based Shift Grouped Pixel to Boundary
// Version: .5
// Desc: Incomplete filter.
// Keywords:
// URL:
// Help:
#region UICode
DoubleSliderControl positionperc = 0; // [-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;

void PreRender(Surface dst, Surface src)
{
    int w = src.Width, h = src.Height;
    if (rowNonZeroAlphas == null)
    {
        columnNonZeroAlphas = new int[w];
        rowNonZeroAlphas = new int[h];
        for (int x = 0; x < w; x++)
        {
            int nonZeroAlphaCount = 0;
            for (int y = 0; y < h; y++)
            {
                if (src[x,y].A >= alpha_threshold) {nonZeroAlphaCount++;}
                columnNonZeroAlphas[x] = nonZeroAlphaCount;
                dst[x,y]=ColorBgra.FromBgra(0,0,0,0);
            }
        }
        for (int y = 0; y < h; y++)
        {
            int nonZeroAlphaCount = 0;
            for (int x = 0; x < w; x++)
            {
                if (src[x,y].A >= alpha_threshold) {nonZeroAlphaCount++;}
                rowNonZeroAlphas[y] = nonZeroAlphaCount;
            }
        }        
    }
    else
    {
        for (int x = 0; x < w; x++)
        {
            for (int y = 0; y < h; y++)
            {
                dst[x,y]=ColorBgra.FromBgra(0,0,0,0);
            }
        }
    }
}

void Render(Surface dst, Surface src, Rectangle rect)
{
    double position = (positionperc / 100 + 1) / 2;
    double influence_factor = influenceperc / 100;
    double invert_factor = 1 - influence_factor;
    int w = rect.Right;
    int h = rect.Bottom;
    int tx,ty,nx,ny,fx,fy,N;
    double tny,tnx;
    
    if (axis==1)
        {
            for (int x = 0; x < w; x++)
            {
                if (IsCancelRequested) return;
                ny = h - 1;
                if (columnNonZeroAlphas[x] != 0)
                {
                    N=columnNonZeroAlphas[x];
                    ty = h - N ;
                    ny-=(int)(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.Ceiling(tny));
                                }
                                else
                                {
                                fy=(int)(Math.Floor(tny));
                                }
                                N--;
                                dst[x,fy] = src[x,y];
                                ny--;
                           }
                        }
                        else
                        {break;}
                    }
                }
            }
        }
    else
        {
            for (int y = 0; y < h; y++)
            {
                if (IsCancelRequested) return;
                nx = 0;
                if (rowNonZeroAlphas[y] != 0)
                {
                    N=rowNonZeroAlphas[y];
                    tx = w - N ;
                    nx+=(int)(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 == 0)
                                {
                                fx=(int)(Math.Ceiling(tnx));
                                }
                                else
                                {
                                fx=(int)(Math.Floor(tnx));
                                }
                                N--;
                                dst[fx,y] = src[x,y];
                                nx++;
                           }
                        }
                        else
                        {break;}
                    }
                }
            }
        }
}

 

 

Edited by Reptillian

G'MIC Filter Developer

Link to comment
Share on other sites

One thing I noticed is that in PreRender you have:

dst[x,y]=ColorBgra.FromBgra(0,0,0,0);

 

I don't think that's kosher. As far as I know, you can only write to the destination buffer in Render, and then only within the Rectangle-Of-Interest.

Link to comment
Share on other sites

6 minutes ago, MJW said:

One thing I noticed is that in PreRender you have:


dst[x,y]=ColorBgra.FromBgra(0,0,0,0);

 

I don't think that's kosher. As far as I know, you can only write to the destination buffer in Render, and then only within the Rectangle-Of-Interest.

 

Then, that must be part of the problem. I wanted to clear dst surface to zero as I noticed problem without doing that. The rectangle of interest is another thing that should have worked, and I checked with G'MIC-QT version of the filter, and checked the numbers of non-zero alpha between the shifted version and the non-shifted version. The expected result is exactly like the G'MIC-QT version. The code should be identical now. So, I'm lost there too.

Edited by Reptillian

G'MIC Filter Developer

Link to comment
Share on other sites

Also,

 for (int x = 0; x < w; x++)
 {
    int nonZeroAlphaCount = 0;
    for (int y = 0; y < h; y++)
    {
        if (src[x,y].A >= alpha_threshold) {nonZeroAlphaCount++;}
        columnNonZeroAlphas[x] = nonZeroAlphaCount;
        //dst[x,y]=ColorBgra.FromBgra(0,0,0,0);
    }
}

Would be better as:

 for (int x = 0; x < w; x++)
 {
    int nonZeroAlphaCount = 0;
    for (int y = 0; y < h; y++)
    {
        if (src[x,y].A >= alpha_threshold) {nonZeroAlphaCount++;}
        //dst[x,y]=ColorBgra.FromBgra(0,0,0,0);
    }
    columnNonZeroAlphas[x] = nonZeroAlphaCount;
}

The point of using a local variable to accumulate the count is to avoid an array index. It's probably not worth the effort, and could be the simpler:

for (int x = 0; x < w; x++)
 {
    int nonZeroAlphaCount = 0;
    for (int y = 0; y < h; y++)
    {
        if (src[x,y].A >= alpha_threshold)
           columnNonZeroAlphas[x]++;
        //dst[x,y]=ColorBgra.FromBgra(0,0,0,0);
    }
}

 

Link to comment
Share on other sites

16 minutes ago, Reptillian said:

 

Then, that must be part of the problem. I wanted to clear dst surface to zero as I noticed problem without doing that.

 

Assuming dst can't be written in PreRender() (as I believe it can't), you've got to figure out a way to do it in Render(). It that's impossible, you need to use an auxiliary surface, do the rendering to it in PreRender(), and copy the results to dst in Render(). That's not ideal, but it's necessary for algorithms that only go in the source-to-destination direction; that is, algorithms where you can't take the destination coordinates, and figure out what color should be there.

Link to comment
Share on other sites

Just now, MJW said:

 

Assuming dst can't be written in PreRender, you've got to figure out a way to do it in Render. It that's impossible, you need to use an auxiliary surface, do the rendering to it in PreRender, and cop the resuts to dst in Render. That's not ideal, but it's necessary for algorithms that only go in the source-to-destination direction; that is, algorithms where you can't take the destination coordinates, and figure out what color should be there.

 

In other words, I have to start over again. Okay, I'll attempt that some time later.

G'MIC Filter Developer

Link to comment
Share on other sites

21 minutes ago, MJW said:

As far as I know, you can only write to the destination buffer in Render, and then only within the Rectangle-Of-Interest.

 

You can write to the destination buffer in both PreRender and Render, but you have to restrict your writes to the selection bounds in both cases.

Writing outside of the selection breaks the undo command.

 

2 minutes ago, MJW said:

It that's impossible, you need to use an auxiliary surface, do the rendering to it in PreRender, and cop the resuts to dst in Render. That's not ideal, but it's necessary for algorithms that only go in the source-to-destination direction; that is, algorithms where you can't take the destination coordinates, and figure out what color should be there.

 

After looking at the code, that is what I would suggest. 

I will test that after I update CodeLab.

  • Like 1

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

14 minutes ago, null54 said:

You can write to the destination buffer in both PreRender and Render, but you have to restrict your writes to the selection bounds in both cases.

Writing outside of the selection breaks the undo command.

 

I didn't know that. Or if I knew it at one time, I'd forgotten it.

 

In the plugin under discussion, I doubt writing to dst in PreRender() makes sense, anyhow. If the algorithm itself can be done in Render(), so can the clears. I doubt the clears in PreRender() even make sense. I bet they're just a band aid that reduces what ever problem Reptillian is seeing.

 

 

 

 

Link to comment
Share on other sites

18 minutes ago, Reptillian said:

In other words, I have to start over again. Okay, I'll attempt that some time later.

 

Not really start over. It would mostly be a matter of moving code from one routine to another.

 

I wish I understood better what the code is doing; but I have great difficulty reading poorly-formatted code. (In fact, I have difficulty reading code not formatted in by preferred indentation style.)

Link to comment
Share on other sites

19 minutes ago, null54 said:

You can write to the destination buffer in ...PreRender

 

Don't do that.

 

I used to think it was ok. Now, I don't.

 

Currently CodeLab allows you do design plugins this way using the File > New templates... I will be correcting this for the next release.

 

Do not use DST as another scratch surface.  Stuff doesn't work right when you do this.

 

 

 

  • Like 1
Link to comment
Share on other sites

After looking through the code more carefully, I notice:

dst[fx,y] = src[x,y];

That's a sure sign the call to Render() may write outside its ROI, which shouldn't be done. Either the algorithm needs to be redone (unlikely), or you need to use an aux surface.

 

Usually, the Render() code when using an aux surface is trivial. Inside the render loops is simply: dst[x, y] = aux[x, y].

 

In some cases, it's possible to save some of the computations for Render() to do. It's good to do as much in Render as possible, since it's done in parallel, where PreRender() is not. Also Render() properly updates the progress bar.

 

Also, aux doesn't have to be an actual surface. In many cases a two-dimensional array of ColorBgras works just as well, and doesn't need to be carefully disposed of. Sometimes a 2D array of floats or ints is better, leaving it to Render() to compute the color from the value in the array. For this algorithm, it could be an array of 2D indexes that tell where in the source buffer the proper color is located. (That's just an example, not a recommendation.)

 

 

Link to comment
Share on other sites

@MJW Your solution worked!

 

Releasing the code here for testing purpose.

 

 

// Name: Axis-Based Shift Grouped Pixel to Boundary
// Submenu: Effects / Distortion
// Author: Reptorian
// Title: Axis-Based Shift Grouped Pixel to Boundary
// Version: 1.0
// Desc: Extended version of Gravity by MadJik. 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] ;
        }
    }
}

 

 

 

Edited by Reptillian
  • Like 1

G'MIC Filter Developer

Link to comment
Share on other sites

4 hours ago, null54 said:

Writing outside of the selection breaks the undo command.

 

That was fixed in paint.net 4.1.6.

Obviously, writing outside of the selection is still a bad practice, and just wastes compute resources.

  • Like 1

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
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...