Paint.NET - Effects Plugin Template

Updated: April 23, 2007 – Changed references of PdnLib to PaintDotNet.Core in compliance with Paint.NET Version 3.05 and above

After finishing up my Cloud Effect Plugin, I thought it would be a good time to sit down and reflect on the development process of Effect Plugins for Paint.NET. While I am no stranger to coding, I do have a B.S. in C.S., this was my first real exploration into the C# language (most of my background is in C++ and Java, so not too big of a jump), so I will share what I have learned to help others develop their own plugins.

This walkthrough is not for the faint of heart. It contains a lot of code and I am not going to explain all of it. I will tell you what each function is used for in order to get you started on the path of creating your own Paint.NET effect plugin. So sit back and enjoy!

The bottom of this page has a link to a Visual Studio 2005 Project Template. I suggest following the instructions at the bottom to load the template files into Visual Studio 2005 and starting up your own project and then follow along.

Properties

Double-click on the Properties folder in the Solution Explorer to open up your projects property settings.

Application Properties

In the Application Properties tab, make sure the Output Type is set to Class Library.

  • Assembly Name: The Name of Your Effect
  • Default Namespace: Your Namespace
  • Output Type: Class Library

Assembly Information

To reach the Assembly Information, click on the “Assembly Information…” button on the Application tab.

  • Title: The name of your Effect
  • Description: Short description of what your Effect does
  • Company: If you want to identify a company
  • Product: The name of your Effect
  • Copyright: If you want to add a Copyright
  • Trademark: If you want to add a Trademark
  • Assembly Version: Major.Minor.Point.Build
  • File Version: Major.Minor.Point.Build
  • GUIDLeave Blank – Automatically filled at build
  • Neutral Language: (None)
  • Make assembly COM-Visible: Not necessary at this time

References

While creating a new project you will need these minimum references:

  • PaintDotNet.Core (Was called PdnLib before Paint.NET Version 3.05)
  • PaintDotNet.Effects
  • System
  • System.Drawing
  • System.Windows.Forms

PaintDotNet.Core.dll and PaintDotNet.Effects.dll can be found in the Paint.NET directory (typically: C:\Program Files\Paint.NET).

Extending the Effect Class

The Effect Class is the heart of your effect plugin. This class contains the functions necessary to place your effect into the Effects menu and to actually render your effect.

using System;
using System.Collections;
using System.Drawing;
using PaintDotNet;
using PaintDotNet.Effects;
namespace YourNamespace
{
  public class YourEffect
    : PaintDotNet.Effects.Effect
  {
    public static string StaticName
    {
      get
      {
        return "Name of Your Effect";
      }
    }
    public static Bitmap StaticIcon
    {
      get
      {
        return new Bitmap(typeof(YourEffect), "YourEffectIcon.png");
      }
    }
    public YourEffect()
      : base(YourEffect.StaticName, YourEffect.StaticIcon, true)
    {
    }
    public override EffectConfigDialog CreateConfigDialog()
    {
      return new YourEffectConfigDialog();
    }
    public override void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length)
    {
      PdnRegion selectionRegion = EnvironmentParameters.GetSelection(srcArgs.Bounds);
      for (int i = startIndex; i < startIndex + length; ++i)
      {
        Rectangle rect = rois[i];
        for (int y = rect.Top; y < rect.Bottom; ++y)
        {
          for (int x = rect.Left; x < rect.Right; ++x)
          {
            // Render Code Here
          }
        }
      }
    }
  }
}

public static string StaticName – this public data member should contain the name of your effect plugin, as you would like it to appear in the Effects menu.

public static Bitmap StaticIcon – this public data member should reference your effect’s icon. When adding your icon to your project, make sure to set the Build Action to Embedded Resource.

public YourEffect() – this public function should extend the base Effect class. There are about 12 different base classes that you can extend (Intellisense should help). The one extended in this example passes the effect name, icon, and sets the isConfigurable option to true (meaning it has a Configuration Dialog).

public override EffectConfigDialog CreateConfigDialog() – this public function should return an instance of your Configuration Dialog. Only needed if the effectisConfigurable.

public override void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length) – this is the render function you will override that will contain the code to your effect.

Extending the EffectConfigToken Class

The EffectConfigToken is a data member that is passed between the Configuration Dialog and the Render function. All user editable parameters should kept in this class.

using System;
namespace YourNamespace
{
  public class YourEffectConfigToken
    : PaintDotNet.Effects.EffectConfigToken
  {
    public YourEffectConfigToken()
      : base()
    {
    }
    protected YourEffectConfigToken(YourEffectConfigToken copyMe)
      : base(copyMe)
    {
      // this.variable = copyMe.variable;
    }
    public override object Clone()
    {
      return new YourEffectConfigToken(this);
    }
  }
}

public YourEffectConfigToken() – the constructor. Set defaults here. Extends the EffectConfigToken base class.

protected YourEffectConfigToken(YourEffectConfigToken copyMe) – function used within Clone() to duplicate the configuration token.

public override object Clone() – override the Clone() function.

Extending the EffectConfigDialog Class

This class is only necessary if your effect isConfigurable… which it should be, because otherwise, you could just create your effect within the Code Lab and save yourself a lot of extra work. That is unless you want a pretty icon next to your effect’s name in the effect menu…

Note: while it is possible to write a lot of code here to build your configuration dialog, it is easier to use Visual Studio 2005’s “visual” aspect and build your dialog interactively. Double-clicking on the controls you add to the dialog will automatically add the most common event trigger and code segment for you to update.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace YourNamespace
{
  public class YourEffectConfigDialog
    : PaintDotNet.Effects.EffectConfigDialog
  {
    private Button buttonOK;
    private Button buttonCancel;
    public EffectPluginConfigDialog()
    {
      InitializeComponent();
    }
    protected override void InitialInitToken()
    {
      theEffectToken = new YourEffectConfigToken();
    }
    protected override void InitTokenFromDialog()
    {
      // ((YourEffectConfigToken)EffectToken).variable = dialogVariable;
    }
    protected override void InitDialogFromToken(EffectConfigToken effectToken)
    {
      // YourEffectConfigToken token = (*YourEffectConfigToken*)effectToken;
      // dialogVariable = token.variable;
    }
    private void InitializeComponent()
    {
      this.buttonCancel = new System.Windows.Forms.Button();
      this.buttonOK = new System.Windows.Forms.Button();
      this.SuspendLayout();
      // 
      // buttonCancel
      // 
      this.buttonCancel.Location = new System.Drawing.Point(195, 218);
      this.buttonCancel.Name = "buttonCancel";
      this.buttonCancel.Size = new System.Drawing.Size(75, 23);
      this.buttonCancel.TabIndex = 1;
      this.buttonCancel.Text = "Cancel";
      this.buttonCancel.UseVisualStyleBackColor = true;
      this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click);
      // 
      // buttonOK
      // 
      this.buttonOK.Location = new System.Drawing.Point(114, 218);
      this.buttonOK.Name = "buttonOK";
      this.buttonOK.Size = new System.Drawing.Size(75, 23);
      this.buttonOK.TabIndex = 2;
      this.buttonOK.Text = "OK";
      this.buttonOK.UseVisualStyleBackColor = true;
      this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click);
      // 
      // YourEffectConfigDialog
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
      this.ClientSize = new System.Drawing.Size(282, 253);
      this.Controls.Add(this.buttonOK);
      this.Controls.Add(this.buttonCancel);
      this.Name = "Name of Your Effect";
      this.Controls.SetChildIndex(this.buttonCancel, 0);
      this.Controls.SetChildIndex(this.buttonOK, 0);
      this.ResumeLayout(false);
    }
    private void buttonOK_Click(object sender, EventArgs e)
    {
      FinishTokenUpdate();
      DialogResult = DialogResult.OK;
      this.Close();
    }
    private void buttonCancel_Click(object sender, EventArgs e)
    {
      this.Close();
    }
  }
}

public EffectPluginConfigDialog() – the constructor. This needs to call InitializeComponent(); to build your dialog.

protected override void InitialInitToken() – override the base function to initialize theEffectToken with a new instance of you EffectConfigToken.

protected override void InitTokenFromDialog() – override the base function to set the EffectToken based on values from the dialog.

protected override void InitDialogFromToken(EffectConfigToken effectToken) – override the base function to set the dialog based on values from theEffectConfigToken.

private void buttonOK_Click(object sender, EventArgs e) – your “OK” button’s “Click” event should call FinishTokenUpdate(), set the DialogResult toDialogResult.OK, and finally close the window with this.Close().

private void buttonCancel_Click(object sender, EventArgs e) – your “Cancel” button’s “Click” event should just close the dialog window with this.Close().

Within any other events, the only statement you need to include within the function block is FinishTokenUpdate();. This calls InitTokenFromDialog() which shouldcontain you code to properly update the EffectToken based on values from the dialog.

Note: the code contained in the template can be built as is, but it won’t yield you any interesting effects. In fact, it will just render a configuration dialog box with “OK” and “Cancel” buttons that do nothing to alter the canvas.

Effects Plugin Template Files

  • Effects Plugin Template – zip files and save into your Visual Studio 2005 “Project Templates” directory (typically: My Documents\Visual Studio 2005\Templates\ProjectTemplates\)