BoltBait's Pages - Outline Object

Sarcasm, just one of the services I offer.

I had started this plugin a long time ago but never finished it.  Then Paint.NET forum user Pyrochild made a plugin to do the same thing, basically, so I shelved it.  Yesterday, I finished it so I'm posting it here.


The Idea

My first thought was to Gaussian Blur the current layer and changed it to the Primary color.  Then, if anit-alias is not selected, changed the alpha to 255.  That's basically the algorithm, but I had to tweak it a little to make the anti-alias show up a lot less--it was way too much.  I'm still not happy with it.  But, I'm tired of playing with it, so here it is...


The Effect DLL

You can download the precompiled effect DLL here: Outline.dll

Just drop this file in your \program files\Paint.NET\effects directory and you should be all set.

If you need help installing effects, read this page: Installing Effects 


Instructions for Use

To use this plugin, you must have an image that includes some transparent area surrounding the object you want to outline.  Usually, text on an otherwise empty layer works best:

1.  Select the color of the outline using the standard color docker window.

2.  Run the Effects > Object > Outline effect.

3.  Adjust the width slider for desired effect.

4.  Check the "Swap Colors" check box to use your secondary color instead of your primary color.

5.  Click OK to finalize your image. 

You can turn off Anti-Alias, if you want, and use Feather instead.


Source Code

This is not a codelab script.  In fact, I'm only showing you the render loop.  The rest is just for UI support:

private BlurEffect blurEffect = new BlurEffect();
private UserBlendOps.NormalBlendOp normalBlendOp = new UserBlendOps.NormalBlendOp(); 

public override unsafe void Render(EffectConfigToken parameters, RenderArgs dstArgs, 
RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length) { EffectPluginConfigToken token = (EffectPluginConfigToken)parameters; ColorBgra OutlineColor = EnvironmentParameters.PrimaryColor; if (token.SwapColors) { OutlineColor = EnvironmentParameters.SecondaryColor; } AmountEffectConfigToken blurToken = new AmountEffectConfigToken(token.OutlineWidth); this.blurEffect.Render(blurToken, dstArgs, srcArgs, rois, startIndex, length); for (int i = startIndex; i < startIndex + length; ++i) { Rectangle roi = rois[i]; for (int y = roi.Top; y < roi.Bottom; ++y) { ColorBgra* srcPtr = srcArgs.Surface.GetPointAddress(roi.X, roi.Y); ColorBgra* dstPtr = dstArgs.Surface.GetPointAddress(roi.X, roi.Y); for (int x = roi.Left; x < roi.Right; ++x) { ColorBgra myPixel = *dstPtr; myPixel.R = OutlineColor.R; myPixel.G = OutlineColor.G; myPixel.B = OutlineColor.B; myPixel.A = Utility.ClampToByte((int)myPixel.A * (48 +
token.OutlineWidth)); if (myPixel.A != 0) { if (!token.AntiAlias) { myPixel.A = 255; } } *dstPtr = this.normalBlendOp.Apply(myPixel, *srcPtr); ++srcPtr; ++dstPtr; } } } }

Monday, February 18, 2008