Jump to content

From CodeLab to VS C# using IndirectUI by example


MadJik

Recommended Posts

This is the result of some discussions with Bleek II who wanted to create a new plugin.

He is the author of the plugin, and he autorized me to publish my version and to publish as well this guide using his original code.

Thanks Bleek II!

This guide will help you to transform a working code in the codelab, into a compiled DLL using VS 2008 C# Express and using the indirectUI possibilities.

You could need this to follow the guide:

http://forums.getpaint.net/index.php?showtopic=3978

From CodeLab to VS2008 C# Express using indirectUI.

1.

First of all, I always started with existing sources of plugin.

Copy/Paste the folder of the source.

Example : Majority,

2.

rename the new folder to the new plugin name: Displacement

4.

Right-click on the folder and choose search, search for everything *.*

5.

Delete every non-source files/folders

I've created the CLEARDLL.BAT to do most of this (in binrelease)

You could delete the *.sln and *.suo

This is the folder list after cleaning:

G:Paint.NETEffectsSourcesDisplacement
| Resource.Designer.cs
| Strings.Designer.cs
| Strings.resx
| Resource.resx
| Majority.csproj
| Majority.cs
|
+-G:Paint.NETEffectsSourcesDisplacementResources
 | Icon.png
 |
 G:Paint.NETEffectsSourcesDisplacementProperties
 | Resources.Designer.cs
 | Resources.resx
 | AssemblyInfo.cs
 G:Paint.NETEffectsSourcesDisplacementbin
 |
 +-G:Paint.NETEffectsSourcesDisplacementbinRelease
   | copyDLL.bat
   | copyDLL_2.bat
   | ClearDLL.bat

6.

Rename every Majority*.* files to Displacement*.*

with this template, you only have 2 files to rename

| Majority.csproj ==> Displacement.csproj

| Majority.cs ==> Displacement.cs

7.

Using a text editor able to search/remplace text in multiple files in a folder/sub-folders,

I search:Majority and replace:Displacement.

8.

Update (at any time) the icon in the resources folder: Icon.png

The name must be Icon.png (or you'll have a broken link to update)

9.

Click on the Displacement.csproj to open VS and start to edit the code.

10.

Check if all the references are ok.

11.

Display the Displacement.cs

I've added Lines'number...

001 : using PaintDotNet;
002 : using PaintDotNet.IndirectUI;
003 : using PaintDotNet.Effects;
004 : using PaintDotNet.PropertySystem;
005 : using System;
006 : using System.Collections.Generic;
007 : using System.Drawing;
008 : 
009 : namespace DisplacementEffect
010 : {
011 :   public sealed class DisplacementFx
012 :       : PropertyBasedEffect
013 :   {
014 :     public static Bitmap StaticImage { get { return Displacement.Resource.Displacement; } }
015 : 
016 :     public static string StaticName { get { return "Displacement"; } }
017 : 
018 :     public static string StaticSubMenuName { get { return SubmenuNames.Stylize; } }
019 : 
020 :     public enum PropertyNames
021 :     {
022 :       Choice,
023 :       Radius,
024 :       Tolerance,
025 :       Alpha
026 :     }
027 : 
028 :     public enum ChoiceList
029 :     {
030 :       Keep=0,
031 :       Primal=1,
032 :       BandW=2
033 :     }
034 : 
035 :     public DisplacementFx()
036 :       : base(StaticName, StaticImage, StaticSubMenuName, EffectFlags.Configurable)
037 :     {
038 :     }
039 : 
040 :     protected override PropertyCollection OnCreatePropertyCollection()
041 :     {
042 :       List<Property> props = new List<Property>();
043 :       props.Add(StaticListChoiceProperty.CreateForEnum<ChoiceList>(PropertyNames.Choice, ChoiceList.Keep, false));
044 :       props.Add(new Int32Property(PropertyNames.Radius, 2, 1, 20));
045 :       props.Add(new Int32Property(PropertyNames.Tolerance, 127, 0, 255));
046 :       props.Add(new BooleanProperty(PropertyNames.Alpha, false));
047 :       return new PropertyCollection(props);
048 :     }
049 : 
050 :     protected override ControlInfo OnCreateConfigUI(PropertyCollection props)
051 :     {
052 :       ControlInfo configUI = CreateDefaultConfigUI(props);
053 : 
054 :       configUI.SetPropertyControlValue(PropertyNames.Choice, ControlInfoPropertyNames.DisplayName, "Choose the color mode");
055 :       PropertyControlInfo pci = configUI.FindControlForPropertyName(PropertyNames.Choice);
056 :       pci.SetValueDisplayName(ChoiceList.Keep, "Keep original colors");
057 :       pci.SetValueDisplayName(ChoiceList.Primal, "Reduce to primal colors");
058 :       pci.SetValueDisplayName(ChoiceList.BandW, "Reduce to black and white");
059 :       configUI.SetPropertyControlType(PropertyNames.Choice, PropertyControlType.RadioButton);
060 : 
061 :       configUI.SetPropertyControlValue(PropertyNames.Radius, ControlInfoPropertyNames.DisplayName, "Radius of analyse");
062 :       configUI.SetPropertyControlValue(PropertyNames.Radius, ControlInfoPropertyNames.SliderLargeChange, 5);
063 :       configUI.SetPropertyControlValue(PropertyNames.Radius, ControlInfoPropertyNames.SliderSmallChange, 1);
064 :       configUI.SetPropertyControlValue(PropertyNames.Radius, ControlInfoPropertyNames.UpDownIncrement, 1);
065 : 
066 :       configUI.SetPropertyControlValue(PropertyNames.Tolerance, ControlInfoPropertyNames.DisplayName, "Color tolerance level");
067 :       configUI.SetPropertyControlValue(PropertyNames.Tolerance, ControlInfoPropertyNames.SliderLargeChange, 5);
068 :       configUI.SetPropertyControlValue(PropertyNames.Tolerance, ControlInfoPropertyNames.SliderSmallChange, 1);
069 :       configUI.SetPropertyControlValue(PropertyNames.Tolerance, ControlInfoPropertyNames.UpDownIncrement, 1);
070 : 
071 :       configUI.SetPropertyControlValue(PropertyNames.Alpha, ControlInfoPropertyNames.DisplayName, "Include transparent pixels");
072 :       configUI.SetPropertyControlValue(PropertyNames.Alpha, ControlInfoPropertyNames.Description, "OFF:no ON:yes");
073 : 
074 :       return configUI;
075 :     }
076 : 
077 :     private int Value1;
078 :     private int Value2;
079 :     private int Value3;
080 :     private bool Value4;
081 : 
082 :     protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
083 :     {
084 :       this.Value1 = (int)newToken.GetProperty<StaticListChoiceProperty>(PropertyNames.Choice).Value;
085 :       this.Value2 = newToken.GetProperty<Int32Property>(PropertyNames.Radius).Value;
086 :       this.Value3 = newToken.GetProperty<Int32Property>(PropertyNames.Tolerance).Value;
087 :       this.Value4 = newToken.GetProperty<BooleanProperty>(PropertyNames.Alpha).Value;
088 :       base.OnSetRenderInfo(newToken, dstArgs, srcArgs);
089 :     }
090 : 
091 :     protected unsafe override void OnRender(Rectangle[] rois, int startIndex, int length)
092 :     {
093 :       for (int i = startIndex; i < startIndex + length; ++i)
094 :       {
095 :         Rectangle rect = rois[i];
096 :         RenderRI(DstArgs.Surface, SrcArgs.Surface, rect);
097 :       }
098 :     }
099 :     void RenderRI(Surface dst, Surface src, Rectangle rect)
100 :     {
101 :       PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);
102 :       Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();
103 : 
104 :       for (int y = rect.Top; y < rect.Bottom; y++)
105 :       {
106 :         for (int x = rect.Left; x < rect.Right; x++)
107 :         {
108 :           dst[x, y] = src[x, y];
109 :         }
110 :       }
111 : 
112 :       ColorBgra CurrentPixel;
113 :       for (int y = rect.Top; y < rect.Bottom; y++)
114 :       {
115 :         int y1 = y - Value2; if (y1 < selection.Top) y1 = selection.Top;
116 :         int y2 = y + Value2; if (y2 > selection.Bottom) y2 = selection.Bottom;
117 :         for (int x = rect.Left; x < rect.Right; x++)
118 :         {
119 :           int x1 = x - Value2; if (x1 < selection.Left) x1 = selection.Left;
120 :           int x2 = x + Value2; if (x2 > selection.Right) x2 = selection.Right;
121 :           int colR = 0, colRmax = 255, colRmin = 0;
122 :           int colG = 0, colGmax = 255, colGmin = 0;
123 :           int colB = 0, colBmax = 255, colBmin = 0;
124 :           int colA = 0, colAmax = 255, colAmin = 0;
125 :           int colN = 0;
126 : 
127 :           for (int y0 = y1; y0 < y2; y0++)
128 :           {
129 :             for (int x0 = x1; x0 < x2; x0++)
130 :             {
131 :               CurrentPixel = src[x0, y0];
132 :               if (CurrentPixel.R > Value3) colR += 2;
133 :               if (CurrentPixel.G > Value3) colG += 2;
134 :               if (CurrentPixel.B > Value3) colB += 2;
135 :               if (Value4) { if (CurrentPixel.A > Value3) colA += 2; }
136 :               if (Value1 != 1)
137 :               {
138 :                 if (CurrentPixel.R > colRmin) { colRmin = (int)CurrentPixel.R; } else { if (CurrentPixel.R < colRmax) { colRmax = (int)CurrentPixel.R; } }
139 :                 if (CurrentPixel.G > colGmin) { colGmin = (int)CurrentPixel.G; } else { if (CurrentPixel.G < colGmax) { colGmax = (int)CurrentPixel.G; } }
140 :                 if (CurrentPixel.B > colBmin) { colBmin = (int)CurrentPixel.B; } else { if (CurrentPixel.B < colBmax) { colBmax = (int)CurrentPixel.B; } }
141 :                 if (Value4) { if (CurrentPixel.A > colAmin) { colAmin = (int)CurrentPixel.A; } else { if (CurrentPixel.A < colAmax) { colAmax = (int)CurrentPixel.A; } } }
142 :               }
143 :               colN += 1;
144 :             }
145 :           }
146 :           CurrentPixel = src[x, y];
147 :           if (Value1 == 2)
148 :           {
149 :             colR = (int)((colR + colG + colB) / 3);
150 :             colG = colR;
151 :             colB = colR;
152 :             colRmin = (int)((colRmin + colGmin + colBmin) / 3);
153 :             colGmin = colRmin;
154 :             colBmin = colRmin;
155 :             colRmax = (int)((colRmax + colGmax + colBmax) / 3);
156 :             colGmax = colRmax;
157 :             colBmax = colRmax;
158 :           }
159 :           if (colN > 1)
160 :           {
161 :             if (colR > colN) { CurrentPixel.R = (byte)colRmax; } else { CurrentPixel.R = (byte)colRmin; }
162 :             if (colG > colN) { CurrentPixel.G = (byte)colGmax; } else { CurrentPixel.G = (byte)colGmin; }
163 :             if (colB > colN) { CurrentPixel.B = (byte)colBmax; } else { CurrentPixel.B = (byte)colBmin; }
164 :             if (Value4) { if (colA > colN) { CurrentPixel.A = (byte)colAmax; } else { CurrentPixel.A = (byte)colAmin; } }
165 :           }
166 :           dst[x, y] = CurrentPixel;
167 :         }
168 :       }
169 :     }
170 :   }
171 : }

12.

Lines 1-7 : the using statments are often the same. If you miss one, you will have a compile error. If one is useless, you wont know!

You could comment them one by one and try to compile to remove the ones that are useless.

Line 14 : usual statement for the Icon (don't need to change it).

Line 16 : the string is the text to appear in the menu.

Line 18 : choose the built-in submenu name, or replace this by a string for a new submenu.

13. Variables:

Each variables (Amountx)

MUST be declared in

..the enum PropertyNames (line 20)

..the PropertyCollection OnCreatePropertyCollection (line 40)

....to define the sequence of the fields in the UI

....to define the type, default value and limits

COULD be declared in

..the ControlInfo OnCreateConfigUI (line 50)

....to add the label and the description

....to define the aspect (radiobutton, colorwheel, anglechooser)

MUST have a receiver in the private list of variable (line 77)

..You could use Caps/nocaps to give them a similar but different name (Amount1 and amount1).

MUST be moved from UI to receiver in the OnSetRenderInfo (line 82)

14.

Lines 91-99 shouldn't be changed. They give a better support to import CodeLab.

There is the loop for the Rect...

15. Copy/Paste the codelab

Your codelab will take place lines 100 to 168.

Copy your code from the first { to the last } / Paste over lines 100-168.

16.

Edit the names and the code to fit with the new list of variables.

17. Final Code:

using PaintDotNet;
using PaintDotNet.IndirectUI;
using PaintDotNet.Effects;
using PaintDotNet.PropertySystem;
using System;
using System.Collections.Generic;
using System.Drawing;

namespace DisplacementEffect
{
 public sealed class DisplacementFx
     : PropertyBasedEffect
 {
   public static Bitmap StaticImage { get { return Displacement.Resource.Displacement; } }

   public static string StaticName { get { return "Displacement"; } }

   public static string StaticSubMenuName { get { return SubmenuNames.Distort; } }

   public enum PropertyNames
   {
     XDistort,
     YDistort,
     Channel,
     Wrap
   }

   public enum ChoiceList
   {
     Alpha=0,
     Grey=1,
     Red=2,
     Green=3,
     Blue=4
   }

   public DisplacementFx()
     : base(StaticName, StaticImage, StaticSubMenuName, EffectFlags.Configurable)
   {
   }

   protected override PropertyCollection OnCreatePropertyCollection()
   {
     List<Property> props = new List<Property>();
     props.Add(new DoubleProperty(PropertyNames.XDistort, 0, -500.0, 500.0));
     props.Add(new DoubleProperty(PropertyNames.YDistort, 0, -500.0, 500.0));
     props.Add(StaticListChoiceProperty.CreateForEnum<ChoiceList>(PropertyNames.Channel, ChoiceList.Grey, false));
     props.Add(new BooleanProperty(PropertyNames.Wrap, false));
     return new PropertyCollection(props);
   }

   protected override ControlInfo OnCreateConfigUI(PropertyCollection props)
   {
     ControlInfo configUI = CreateDefaultConfigUI(props);

     configUI.SetPropertyControlValue(PropertyNames.XDistort, ControlInfoPropertyNames.DisplayName, "X Distort in %");

     configUI.SetPropertyControlValue(PropertyNames.YDistort, ControlInfoPropertyNames.DisplayName, "Y Distort in %");

     configUI.SetPropertyControlValue(PropertyNames.Channel, ControlInfoPropertyNames.DisplayName, "Choose the channel");
     PropertyControlInfo pci = configUI.FindControlForPropertyName(PropertyNames.Channel);
     pci.SetValueDisplayName(ChoiceList.Grey, "Average of RBG");
     configUI.SetPropertyControlType(PropertyNames.Channel, PropertyControlType.RadioButton);

     configUI.SetPropertyControlValue(PropertyNames.Wrap, ControlInfoPropertyNames.DisplayName, "Wrap around the borders?");
     configUI.SetPropertyControlValue(PropertyNames.Wrap, ControlInfoPropertyNames.Description, "OFF:no ON:yes");

     return configUI;
   }

   private double xdistort;
   private double ydistort;
   private int channel;
   private bool wrap;

   protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
   {
     this.xdistort = newToken.GetProperty<DoubleProperty>(PropertyNames.XDistort).Value;
     this.ydistort = newToken.GetProperty<DoubleProperty>(PropertyNames.YDistort).Value;
     this.channel = (int)newToken.GetProperty<StaticListChoiceProperty>(PropertyNames.Channel).Value;
     this.wrap = newToken.GetProperty<BooleanProperty>(PropertyNames.Wrap).Value;
     base.OnSetRenderInfo(newToken, dstArgs, srcArgs);
   }

   protected override void OnRender(Rectangle[] rois, int startIndex, int length)
   {
     for (int i = startIndex; i < startIndex + length; ++i)
     {
       Rectangle rect = rois[i];
       RenderRI(DstArgs.Surface, SrcArgs.Surface, rect);
     }
   }
   void RenderRI(Surface dst, Surface src, Rectangle rect)
   {
     PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);
     Rectangle selection = EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();

     ColorBgra CP;
     float dif1, dif2, amo1, amo2;
     int fx = 0;

     //amo1 = (float)Amount1 / 100f;
     //amo2 = (float)Amount2 / 100f;
     amo1 = (float)xdistort / 100f;
     amo2 = (float)ydistort / 100f;

     for (int y = rect.Top; y < rect.Bottom; ++y)
     {
       for (int x = rect.Left; x < rect.Right; ++x)
       {
         CP = src[x, y];
         //switch (Amount3)
         switch (channel)
         {
         case 0:
           fx = CP.A;
           break;
         case 1:
           fx = (CP.R + CP.G + CP. / 3;
           break;
         case 2:
           fx = CP.R;
           break;
         case 3:
           fx = CP.G;
           break;
         case 4:
           fx = CP.B;
           break;
         default:
           fx = CP.R;
           break;
         }
         dif1 = x + amo1 * (fx - 127);
         dif2 = y + amo2 * (fx - 127);

         //if (Amount4 != 1)
         if (!wrap)
         {
           if ((dif1 >= selection.Right) || (dif1 < selection.Left)) dif1 = x;
           if ((dif2 >= selection.Bottom) || (dif2 < selection.Top)) dif2 = y;
         }
         //dst[x, y] = src.GetBilinearSample(dif1, dif2, true);
         dst[x, y] = src.GetBilinearSample(dif1, dif2);
       }
     }
   }
 }
}

18. Build it!

:Warning: Close Paint.net if it is open!

In Visual C# express 2008, press F6 to build the DLL

It will ask the first time to create the displacement.sln file, save with default...

If no error you will have "Built succeeded".

You could find a DLL in the subfolder binrelease.

You could adapt the CopyDLL.bat to copy it to the c:program filepaint.neteffects

(I copy it twice because I want a copy of the effect folder on my USB Disk G: )

Or copy it manually

Or change the proprities of the project to make it build directly in the effect folder (I don't like this)

19. test it!...

Link to comment
Share on other sites

Following the steps here was a huge help in learning VS08. I just want to point out that I'm Bleek II... not Bleed, hahaha. Bleek II is short for me real name, Brian Lee Kloosterman II (B. Lee K. II). I just felt I needed to explain this so I didn't seem "emo"... or whatever.

Link to comment
Share on other sites

  • 10 months later...

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...