Jump to content

Complex ink drawing effect - beta


Red ochre

Recommended Posts

I'm working on the attached plugin (which creates various types of ink outline). The problem I can't solve, is in the 'enhancements' section, where I am trying to remove isolated pixels and add in pixels to fill gaps. I'm doing this by 'looking' at the surrounding pixels - However, I think the rectangle of interest is stopping it seeing around the current pixel when it borders 2 ROIs.

I am testing the plugin by marking line pixels that have been added in, red, and those removed, cyan. If you zoom right in on the attached image you will see where it's going wrong.

I have tried the 'g.clip' code with no effect and really think I need someway of making it consider the whole whole image as 1 ROI to avoid this. Of course it could be due to something else.

I would be grateful for any ideas on how to solve this. Please bear in mind that I'm very new to C# and this is very much a 'beta' version - it will need a lot of tidying up, but I need to sort this problem first.

Many thanks

complexidtestcotswoldpath.jpg

By the way I think the answer to the question is using a method outside of the render loop - but haven't got back to this yet.

/* =================================================== */
/* 	*/
/* Advanced Beta Ink drawing.cs 	*/
/* (c) 2011 Red Ochre (John Robbins) 	*/
/* 	*/
/* Description: produces various ink outlines 	*/
/* 	*/
/* ========================================== ======== */

// Name: Beta Complex ink drawing
// Author: Red ochre (John Robbins)
// Submenu: Advanced
// URL: http://www.getpaint.net/redirect/plugins.html
// Title: Complex ink drawing - 2011 Red Ochre


#region UICode
byte Amount1 = 0; // detection type|0.darker than blur|1.lighter than blur|2.both (blur)|3.darker by colour (blur)|4.edge detect|5.emboss|6.oil painting|7.relief
int Amount2 = 5; // [1,100] blur radius - smoothness OR edge angle OR brush size
int Amount3 = -100; // [-256,256] dark / bright threshold
byte Amount4 = 0; // outline properties|primary colour|transparent|as original(src)|as detection type(dst)|src greys|dst greys|secondary colour
byte Amount5 = 0; // background properties|secondary colour|transparent|as original(src)|as detection type(dst)|src greys|dst greys|primary colour
int Amount6 = 765; // [0,765] background if tone above this
int Amount7 = 0; // [0,765] background if tone below this
byte Amount8 = 6; // enhancements|none|1....by 4|2..... by 8|3....by 20|4... by 36|5.link lines|6.thicken lines
byte Amount9 = 1; // presets|normal|test mode (red = added pix. cyan = removed)
#endregion
void Render(Surface dst, Surface src, Rectangle rect)
{// Graphics g = new RenderArgs(dst).Graphics;	// this doesn't seem to work as ROI still causes problems
// g.Clip = new Region(rect); 	// comment this code out



if(Amount1 == 0 || Amount1 == 1 || Amount1 == 2 || Amount1 == 3){
// Call the Gaussian Blur effect
GaussianBlurEffect blurEffect = new GaussianBlurEffect();
PropertyCollection bProps = blurEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken bParameters = new PropertyBasedEffectConfigToken(bProps);
bParameters.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount2);
blurEffect.SetRenderInfo(bParameters, new RenderArgs(dst), new RenderArgs(src));
blurEffect.Render(new Rectangle[1] {rect},0,1);}
if(Amount1 == 4){
// Setup for calling the Edge Detect effect
EdgeDetectEffect edgedetectEffect = new EdgeDetectEffect();
PropertyCollection edgeProps = edgedetectEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken EdgeParameters = new PropertyBasedEffectConfigToken(edgeProps);
EdgeParameters.SetPropertyValue(EdgeDetectEffect.PropertyNames.Angle, (double)((50 - Amount2) * 1.8)); 
edgedetectEffect.SetRenderInfo(EdgeParameters, new RenderArgs(dst), new RenderArgs(src));
// Call the Edge Detect function
edgedetectEffect.Render(new Rectangle[1] {rect},0,1);}
if(Amount1 == 5){// Setup for calling the Emboss function
EmbossEffect embossEffect = new EmbossEffect();
PropertyCollection eProps = embossEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken eParameters = new PropertyBasedEffectConfigToken(eProps);
eParameters.SetPropertyValue(EmbossEffect.PropertyNames.Angle, (double)((50 - Amount2) * 1.8)); 
embossEffect.SetRenderInfo(eParameters, new RenderArgs(dst), new RenderArgs(src));
// Call the Emboss function
embossEffect.Render(new Rectangle[1] {rect},0,1);}
if(Amount1 == 6){// Setup for calling the Oil Painting effect
OilPaintingEffect oilpaintEffect = new OilPaintingEffect();
PropertyCollection oilpaintProps = oilpaintEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken oilpaintParameters = new PropertyBasedEffectConfigToken(oilpaintProps);
oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.BrushSize,(int) ((Amount2 * 8) / 100)); 
oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.Coarseness, 3); 
oilpaintEffect.SetRenderInfo(oilpaintParameters, new RenderArgs(dst), new RenderArgs(src));
// Call the Oil Painting function
oilpaintEffect.Render(new Rectangle[1] {rect},0,1);}
if(Amount1 == 7){// Setup for calling the Relief effect
ReliefEffect reliefEffect = new ReliefEffect();
PropertyCollection reliefProps = reliefEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken ReliefParameters = new PropertyBasedEffectConfigToken(reliefProps);
ReliefParameters.SetPropertyValue(ReliefEffect.PropertyNames.Angle, (double)((50 - Amount2) * 1.8)); 
reliefEffect.SetRenderInfo(ReliefParameters, new RenderArgs(dst), new RenderArgs(src));
// Call the Relief function
reliefEffect.Render(new Rectangle[1] {rect},0,1);}



ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;
ColorBgra cp;	// current pixel
ColorBgra dp;	// destination pixel
int B, G, R, A, dB, dG, dR, dA,td,ts,lb,lg,lr,la,bb,bg,br,ba,h,w,r;
int th = Amount3; int th3 = Amount3/3;
int H = rect.Bottom - rect.Top;
int W = rect.Right - rect.Left;
byte A8 = Amount8;
bool[,,]v = new bool[W,H,2];	// hope this is ok. array W by H and true or false * 2
bool l = true; bool b = false;	// l = outline = true; b = background = false

for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 1 analyze src and put result in array sval
	{ for (int x = rect.Left; x < rect.Right; x++) 
	{ 
	h = y - rect.Top;
	w = x - rect.Left;
	cp = src[x,y]; 
	B = (int)cp.B;
	G = (int)cp.G;
	R = (int)cp.R;
	A = (int)cp.A;
	dp = dst[x,y];
	dB = (int)dp.B;
	dG = (int)dp.G;
	dR = (int)dp.R;
	dA = (int)dp.A;

	td = dB + dG + dA;// destination - blurred, edge detected, embossed pixel
	ts = B + G + R;// source - unblurred pixel
	th3 = th / 3;

	if(Amount1 == 0 || Amount1 == 2 || Amount1 == 4 ||Amount1 == 5 ||Amount1 == 6 || Amount1 == 7 || Amount1 == 8)
	{if(ts < td + th && ts > Amount7 && ts <= Amount6){v[w,h,0] = l;}	// if darker (line) then true
	else v[w,h,0] = b;
	}
	if(Amount1 == 1)
	{if(ts > td - th && ts > Amount7 && ts <= Amount6){v[w,h,0] = l;}	// if lighter than blur by amount2 then also true
	else if (Amount1 == 1){ v[w,h,0] = b;}
	}
	if(Amount1 == 2)
	{if((ts < td + th || ts >= td - th) && ts > Amount7 && ts <= Amount6){v[w,h,0] = l;}	// both, if darker (line) or lighter (background)then true
	else if (Amount1 == 2){ v[w,h,0] = b;}
	}
	if(Amount1 == 3)
	{if((B < dB + th3 || G < dG + th3 || R < dR + th3) && ts > Amount7 && ts <= Amount6){v[w,h,0] = l;}	// darker by colour
	else if (Amount1 == 3){ v[w,h,0] = b;}
	}

	v[w,h,1] = v[w,h,0];

	}
	}
if(A8 > 0 )
{for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 2 - changes sval entries remove single pixels
	{ for (int x = rect.Left; x < rect.Right; x++) 
	{ 
	h = y - rect.Top;w = x - rect.Left;
	if(h >= 1 && h < H-1)
	{if(w >= 1 && w < W-1)
	{if(A8 > 0 )
	{if(v[w,h,0] == l && v[w - 1,h	,0] == b &&	// case 1 - by 4
	v[w	,h - 1,0] == b &&
	v[w	,h + 1,0] == b &&
	v[w + 1,h	,0] == b )
	{v[w,h,1] = b;}// if line surrounded by 4 background make background
	if(v[w,h,0] == b && v[w - 1,h	,0] == l &&
	v[w	,h - 1,0] == l &&
	v[w	,h + 1,0] == l &&
	v[w + 1,h	,0] == l )
	{v[w,h,1] = l;}}// if background surrounded by 4 line make line

	if(A8 > 1 )
	{if(v[w,h,0] == l && v[w - 1,h - 1,0] == b &&	// case 2 - by 8
	v[w - 1,h + 1,0] == b &&
	v[w + 1,h - 1,0] == b &&
	v[w + 1,h + 1,0] == b )
	{v[w,h,1] = b;}// if line surrounded by 4 background make background
	if(v[w,h,0] == b && v[w - 1,h - 1 ,0] == l &&
	v[w - 1,h + 1,0] == l &&
	v[w + 1,h - 1,0] == l &&
	v[w + 1,h + 1,0] == l )
	{v[w,h,1] = l;}// if background surrounded by 4 line make line
	}
	}
	}
	if(h >= 2 && h < H - 2)
	{if(w >= 2 && w < W - 2)
	{if(A8 > 2)
	{if(v[w,h,0] == l && v[w - 2,h	,0] == b &&	// case 3 - 20. previous 8 checks & 12 pix perimeter check
	v[w - 2,h - 1,0] == b &&
	v[w - 1,h - 2,0] == b &&
	v[w	,h - 2,0] == b &&
	v[w + 1,h - 2,0] == b &&
	v[w + 2,h - 1,0] == b &&
	v[w + 2,h	,0] == b &&
	v[w + 2,h + 1,0] == b &&
	v[w + 1,h + 2,0] == b &&
	v[w	,h + 2,0] == b &&
	v[w - 1,h + 2,0] == b &&
	v[w - 2,h + 1,0] == b ) 
	{v[w,h,1] = b;} // make background if isolated line pix

	if(v[w,h,0] == b && v[w - 2,h	,0] == l &&	// case 3 - same for sad lonely background pixies
	v[w - 2,h - 1,0] == l &&
	v[w - 1,h - 2,0] == l &&
	v[w	,h - 2,0] == l &&
	v[w + 1,h - 2,0] == l &&
	v[w + 2,h - 1,0] == l &&
	v[w + 2,h	,0] == l &&
	v[w + 2,h + 1,0] == l &&
	v[w + 1,h + 2,0] == l &&
	v[w	,h + 2,0] == l &&
	v[w - 1,h + 2,0] == l &&
	v[w - 2,h + 1,0] == l ) 
	{v[w,h,1] = l;} // make line if isolated background pix

	}
	}
	}
	if(h >= 3 && h < H - 3)
	{if(w >= 3 && w < W - 3)
	{if(A8 > 3)
	{if(v[w,h,0] == l && v[w - 3,h	,0] == b &&	// case 4 - 36. previous 20 checks & 16 pix perimeter check
	v[w - 3,h - 1,0] == b &&
	v[w - 2,h - 2,0] == b &&
	v[w - 1,h - 3,0] == b &&
	v[w	,h - 3,0] == b &&
	v[w + 1,h - 3,0] == b &&
	v[w + 2,h - 2,0] == b &&
	v[w + 3,h - 1,0] == b &&
	v[w + 3,h	,0] == b &&
	v[w + 3,h + 1,0] == b &&
	v[w + 2,h + 2,0] == b &&
	v[w + 1,h + 3,0] == b &&
	v[w	,h + 3,0] == b &&
	v[w - 1,h + 3,0] == b &&
	v[w - 2,h + 2,0] == b &&
	v[w - 3,h + 1,0] == b ) 
	{v[w,h,1] = b;} // make background if isolated line pix
	if(v[w,h,0] == b && v[w - 3,h	,0] == l &&	// case 4 - same for background
	v[w - 3,h - 1,0] == l &&
	v[w - 2,h - 2,0] == l &&
	v[w - 1,h - 3,0] == l &&
	v[w	,h - 3,0] == l &&
	v[w + 1,h - 3,0] == l &&
	v[w + 2,h - 2,0] == l &&
	v[w + 3,h - 1,0] == l &&
	v[w + 3,h	,0] == l &&
	v[w + 3,h + 1,0] == l &&
	v[w + 2,h + 2,0] == l &&
	v[w + 1,h + 3,0] == l &&
	v[w	,h + 3,0] == l &&
	v[w - 1,h + 3,0] == l &&
	v[w - 2,h + 2,0] == l &&
	v[w - 3,h + 1,0] == l ) 
	{v[w,h,1] = l;} // make line if isolated background pix


	}
	}
	}
	if(A8 > 4)	
	{if(h >= 1 && h < H-1)
	{if(w >= 1 && w < W-1)
	{if(A8 > 4)	// case 5 connect lines
	{if(v[w,h,0] == b && v[w - 1,h	,1] == l && v[w + 1,h	,1] == l){v[w,h,1] = l;}
	if(v[w,h,0] == b && v[w	,h - 1,1] == l && v[w + 1,h + 1,1] == l){v[w,h,1] = l;}
	if(v[w,h,0] == b && v[w - 1,h - 1,1] == l && v[w + 1,h + 1,1] == l){v[w,h,1] = l;}
	if(v[w,h,0] == b && v[w - 1,h + 1,1] == l && v[w + 1,h - 1,1] == l){v[w,h,1] = l;}
	}
	// thicken lines case 6
	if(A8 == 6)
	{if(v[w,h,0] == l && v[w,h,1] == l){v[w - 1,h - 1,1] = l;v[w	,h - 1,1] = l;v[w + 1,h - 1,1] = l;
	v[w - 1,h	,1] = l;v[w + 1,h	,1] = l;
	v[w - 1,h + 1,1] = l;v[w	,h + 1,1] = l;v[w + 1,h + 1,1] = l;
	}
	}
	}
	}
	}
	}
	}
}

for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 3 - sets BGRA values, re-assembles and sends to dst canvas
	{ for (int x = rect.Left; x < rect.Right; x++) 
	{ 
	h = y - rect.Top;
	w = x - rect.Left;

	cp = src[x,y]; 
	B = (int)cp.B;
	G = (int)cp.G;
	R = (int)cp.R;
	A = (int)cp.A;

	td = (int)dst[x,y].B +(int)dst[x,y].G + (int)dst[x,y].R;// destination - blurred pixel
	ts = B + G + R;// source - unblurred pixel
	lb = 0; lg = 0; lr = 0; la = 255;	// set initial line variables to black
	bb = 255; bg = 255; br = 255; ba = 255;	// set initial background variables to white


	switch (Amount4)// line properties
	{case 0: lb = PrimaryColor.B; lg = PrimaryColor.G; lr = PrimaryColor.R; la = PrimaryColor.A;break;	//line colour = primary colour default black
	case 1: lb = B; lg = G; lr = R;la = 0;break;	//transparent
	case 2: lb = B; lg = G; lr = R; la = A;break;	// as original
	case 3: lb = dst[x,y].B; lg = dst[x,y].G; lr = dst[x,y].R; la = dst[x,y].A;break;	// as blur
	case 4: lb = (int)(ts / 3);lg = (int)(ts / 3);lr = (int)(ts / 3);la = A;break; // src greys
	case 5: lb = (int)(td / 3);lg = (int)(td / 3);lr = (int)(td / 3);la = A;break; // dst greys
	case 6: lb = SecondaryColor.B;lg = SecondaryColor.G;lr = SecondaryColor.R;la = SecondaryColor.A;break;}// secondary colour

	switch (Amount5)//background properties
	{case 0: bb = SecondaryColor.B; bg = SecondaryColor.G; br = SecondaryColor.R; ba = SecondaryColor.A;break;	//background colour = secondary colour default white
	case 1: bb = B; bg = G; br = R; ba = 0;break;	//transparent
	case 2: bb = B; bg = G; br = R; ba = A;break;	// as original
	case 3: bb = dst[x,y].B; bg = dst[x,y].G; br = dst[x,y].R; ba = dst[x,y].A;break;//as blur
	case 4: bb = (int)(ts / 3);bg = (int)(ts / 3);br = (int)(ts / 3);ba = A;break; // src greys
	case 5: bb = (int)(td / 3);bg = (int)(td / 3);br = (int)(td / 3);ba = A;break; // dst greys
	case 6: bb = PrimaryColor.B; bg = PrimaryColor.G; br = PrimaryColor.R; ba = PrimaryColor.A;break;}// primary

	if(v[w,h,1] ==  {B = bb; G = bg; R = br; A = ba;}//background values
	if(v[w,h,1] == l) {B = lb; G = lg; R = lr; A = la;}//outline values
	if(Amount9 == 1 && v[w,h,0] == l && v[w,h,1] == {B = 128;G = 128; R = 0; A = 255;} // if changed line single pixel make cyan
	if(Amount9 == 1 && v[w,h,0] == b && v[w,h,1] == l){B = 0;G = 0; R = 255; A = 255;} // if changed background single pixel make red




	// re assemble
	cp = ColorBgra.FromBgra( Int32Util.ClampToByte(, Int32Util.ClampToByte(G), Int32Util.ClampToByte(R), Int32Util.ClampToByte(A));
	dst[x,y] = cp;
	}
}
}






















Edited by Red ochre

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

Thanks for the reply.

Sorry, I still don't understand. I'm reading from the src into an array, then changing the values in the array (to avoid unwanted 'feedback'from refencing pixels that will be changed), then using these new values to write to the dst.

At some stage in that process the plugin is deciding that a single 'line' pixel which is surrounded by 'background' pixels - isn't? (when I can see it is !).

Surely if it wasn't writing to dst along the ROI borders, the image would have either solid horizontal lines or lines of the unaltered src image(colour)?

The process does what it should inbetween these borders and on the borders still manages to 'write' the part-processed image - ie black and white. It just isn't changing it to what it should be from the array.

Black or white (from true, true or false, false in the array) & red if added (false, true), cyan if removed (true, false).

Anyway - thanks for the reply - If you can think of anyway round this or any plugins (with published code), which have overcome this problem, I'd be very grateful.

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

  • 1 year later...

Hello again - hope this doesn't count as necroposting!

Well I thought that rewriting the plugin to use methods might solve the ROI problem - it hasn't.

The methods to load and alter the array have to be called from within the render method, as they currently depend upon the dst surface having the blur values. I suppose I could write my own simplified blur function reading from the src surface directly into the array - but I doubt this would solve the problem either.

If anyone can explain how to avoid these ROI effects I'd be very grateful.

Please assume that I am an idiot! - if the explanation is too cryptic I won't understand.

I am totally stumped as this problem depends upon knowledge I don't have - rather than something I could deduce.

I know the forum is not here to teach C#, but this topic seems to be specific to PDN and not explained elsewhere.

Additionally, PDN effects are the only programming that I do. So the only benefit is to PDN users (and myself).

If I cannot overcome this problem in a reliable way then I cannot write more complex effects, which is a shame, because I have some interesting and hopefully useful effects in mind for the future.At the moment it seems like the computer's left hand doesn't know what it's right hand is doing - and producing incorrect logic - but quickly!

I am quite surprised as to why this plugin has problems when my 'Composition tool' (which uses methods called from within the render loop) doesn't? - perhaps I had no need to use a method for that one?

Note: I only use codelab. Also the code below is only 'beta' and will be tidied up considerably if I can sort the ROI problem. In the attached picture the red stripes are where the plugin is doing what it should.

Many thanks in advance - I realise how busy Rick and the experienced plugin writers are currently.

Sorry if the tone is a little disgruntled but this is the third rewrite, with no progress, I'm getting frustrated!

newedge1fROIcotswoldpath.jpg

/* =================================================== */
/* 	*/
/* Newedge.cs 	*/
/* (c) 2011 Red Ochre (John Robbins) 	*/
/* 	*/
/* Description: produces various ink outlines 	*/
/* 	*/
/* ========================================== ======== */

// Name:Newedge
// Author: Red ochre (John Robbins)
// Submenu: Advanced
// URL: http://www.getpaint.net/redirect/plugins.html
// Title: New edge 	Feb 2012 Red Ochre


#region UICode
byte Amount1 = 0; // detection type|0.darker than blur|1.lighter than blur|2.both (blur)
int Amount2 = 1; // [1,100] blur radius - smoothness OR edge angle OR brush size
int Amount3 = -150; // [-256,256] dark / bright threshold
byte Amount4 = 0; // outline properties|primary colour|transparent|as original(src)|as detection type(dst)|src greys|dst greys|secondary colour
byte Amount5 = 0; // background properties|secondary colour|transparent|as original(src)|as detection type(dst)|src greys|dst greys|primary colour
int Amount6 = 765; // [0,765] background if tone above this
int Amount7 = 0; // [0,765] background if tone below this
int Amount8 = 4; // [0,4] remove isolated pixels
int Amount9 = 1; // [0,1] thicken lines
bool Amount10 = true; // [0,1] test: blue = removed, red = added
#endregion

// load array method here
private bool[,,] loadarray (Surface src,Surface dst,Rectangle rect,bool[,,]v,bool l,bool b,int th)
{for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 1 analyze src and put result in array sval
	{ for (int x = rect.Left; x < rect.Right; x++) 
	{ 
	int h = y - rect.Top;
	int w = x - rect.Left;
	ColorBgra cp = src[x,y]; 
	int B = (int)cp.B;
	int G = (int)cp.G;
	int R = (int)cp.R;
	int A = (int)cp.A;
	ColorBgra dp = dst[x,y];
	int dB = (int)dp.B;
	int dG = (int)dp.G;
	int dR = (int)dp.R;
	int dA = (int)dp.A;

	int td = dB + dG + dA;// destination - blurred,
	int ts = B + G + R;// source - unblurred pixel


	if(Amount1 == 0 || Amount1 == 2)
	{if(ts < td + th && ts > Amount7 && ts <= Amount6){v[w,h,0] = l;}	// if darker (line) then true
	else v[w,h,0] = b;
	}
	if(Amount1 == 1)
	{if(ts > td - th && ts > Amount7 && ts <= Amount6){v[w,h,0] = l;}	// if lighter than blur by amount2 then also true
	else if (Amount1 == 1){ v[w,h,0] = b;}
	}
	if(Amount1 == 2)
	{if((ts < td + th || ts >= td - th) && ts > Amount7 && ts <= Amount6){v[w,h,0] = l;}// both, if darker (line) or lighter (background)then true
	else if (Amount1 == 2){ v[w,h,0] = b;}


	}
	v[w,h,1] = v[w,h,0];// simply copy initial values to the 2nd part of array

	}
	}// end of loop1



	return v;
}

// alter array method here
private bool[,,] altarray (Rectangle rect,bool[,,]v,bool l,bool b,int H,int W,int A8)
{for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 2 - changes sval entries remove single pixels
	{ for (int x = rect.Left; x < rect.Right; x++) 
	{ 

int h = y - rect.Top;
int w = x - rect.Left;

	if((h >= 1 && h < H-1) 
	&& (w >= 1 && w < W-1))
	{	
	if(A8 >= 1)// case 1 - by 4
	{
	if(v[w,h,0] == l 
	&& v[w - 1,h	,0] == b 
	&& v[w	,h - 1,0] == b 
	&& v[w	,h + 1,0] == b 
	&& v[w + 1,h	,0] == 
	{v[w,h,1] = b;}// if line surrounded by 4 background make background
	if(v[w,h,0] == b 
	&& v[w - 1,h	,0] == l 
	&& v[w	,h - 1,0] == l 
	&& v[w	,h + 1,0] == l 
	&& v[w + 1,h	,0] == l)
	{v[w,h,1] = l;}// if background surrounded by 4 line make line
	} 	
	if(A8 >= 2)// case 2 - by 8
	{
	if(v[w,h,0] == l 
	&& v[w - 1,h - 1,0] == b 
	&& v[w - 1,h + 1,0] == b 
	&& v[w + 1,h - 1,0] == b 
	&& v[w + 1,h + 1,0] == 
	{v[w,h,1] = b;}// if line surrounded by 4 background make background
	if(v[w,h,0] == b 
	&& v[w - 1,h - 1 ,0] == l 
	&& v[w - 1,h + 1,0] == l 
	&& v[w + 1,h - 1,0] == l 
	&& v[w + 1,h + 1,0] == l)
	{v[w,h,1] = l;}// if background surrounded by 4 line make line
	}
	}

	if((A8 >= 3)
	&&(h >= 2 && h < H - 2)
	&&(w >= 2 && w < W - 2))
	{
	if(v[w,h,0] == l // case 3 - 20. previous 8 checks & 12 pix perimeter check
	&& v[w - 2,h	,0] == b 	
	&& v[w - 2,h - 1,0] == b 
	&& v[w - 1,h - 2,0] == b 
	&& v[w	,h - 2,0] == b 
	&& v[w + 1,h - 2,0] == b 
	&& v[w + 2,h - 1,0] == b 
	&& v[w + 2,h	,0] == b 
	&& v[w + 2,h + 1,0] == b 
	&& v[w + 1,h + 2,0] == b 
	&& v[w	,h + 2,0] == b 
	&& v[w - 1,h + 2,0] == b 
	&& v[w - 2,h + 1,0] == 
	{v[w,h,1] = b;} // make background if isolated line pix

	if(v[w,h,0] == b // case 3 - same for sad lonely background pixies
	&& v[w - 2,h	,0] == l 	
	&& v[w - 2,h - 1,0] == l 
	&& v[w - 1,h - 2,0] == l 
	&& v[w	,h - 2,0] == l 
	&& v[w + 1,h - 2,0] == l 
	&& v[w + 2,h - 1,0] == l 
	&& v[w + 2,h	,0] == l 
	&& v[w + 2,h + 1,0] == l
	&& v[w + 1,h + 2,0] == l 
	&& v[w	,h + 2,0] == l 
	&& v[w - 1,h + 2,0] == l 
	&& v[w - 2,h + 1,0] == l) 
	{v[w,h,1] = l;} // make line if isolated background pix
	}

	if((A8 == 4)	// case 4 - 36. previous 20 checks & 16 pix perimeter check
	&&(h >= 3 && h < H - 3)
	&&(w >= 3 && w < W - 3))

	{
	if(v[w,h,0] == l 
	&& v[w - 3,h	,0] == b 
	&& v[w - 3,h - 1,0] == b 
	&& v[w - 2,h - 2,0] == b 
	&& v[w - 1,h - 3,0] == b 
	&& v[w	,h - 3,0] == b 
	&& v[w + 1,h - 3,0] == b 
	&& v[w + 2,h - 2,0] == b 
	&& v[w + 3,h - 1,0] == b 
	&& v[w + 3,h	,0] == b 
	&& v[w + 3,h + 1,0] == b 
	&& v[w + 2,h + 2,0] == b 
	&& v[w + 1,h + 3,0] == b 
	&& v[w	,h + 3,0] == b 
	&& v[w - 1,h + 3,0] == b 
	&& v[w - 2,h + 2,0] == b 
	&& v[w - 3,h + 1,0] == 
	{v[w,h,1] = b;} // make background if isolated line pix
	if(v[w,h,0] == b // case 4 - same for background
	&& v[w - 3,h	,0] == l 
	&& v[w - 3,h - 1,0] == l 
	&& v[w - 2,h - 2,0] == l 
	&& v[w - 1,h - 3,0] == l 
	&& v[w	,h - 3,0] == l 
	&& v[w + 1,h - 3,0] == l 
	&& v[w + 2,h - 2,0] == l 
	&& v[w + 3,h - 1,0] == l 
	&& v[w + 3,h	,0] == l 
	&& v[w + 3,h + 1,0] == l 
	&& v[w + 2,h + 2,0] == l 
	&& v[w + 1,h + 3,0] == l 
	&& v[w	,h + 3,0] == l 
	&& v[w - 1,h + 3,0] == l 
	&& v[w - 2,h + 2,0] == l 
	&& v[w - 3,h + 1,0] == l) 
	{v[w,h,1] = l;} // make line if isolated background pix
	}}}
return v;
}
// thicken lines method here
private bool[,,]thickenlines(Rectangle rect, bool[,,]v, bool l,bool b,int H,int W)
{for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 3 - changes array values thickenlines
	{ for (int x = rect.Left; x < rect.Right; x++) 
	{ 
	int h = y - rect.Top;
	int w = x - rect.Left;

	if((h >= 1 && h < H - 1)
	&&(w >= 1 && w < W - 1))
	{if(v[w,h,0] == l 
	&& v[w,h,1] == l)
	{v[w - 1,h - 1,1] = l;
	v[w	,h - 1,1] = l;
	v[w + 1,h - 1,1] = l;
	v[w - 1,h	,1] = l;
	v[w + 1,h	,1] = l;
	v[w - 1,h + 1,1] = l;
	v[w	,h + 1,1] = l;
	v[w + 1,h + 1,1] = l;}
	}
	} 
}
return v;
}



void Render(Surface dst, Surface src, Rectangle rect)
{


// Call the Gaussian Blur effect - this can only be done from here as it uses dst
GaussianBlurEffect blurEffect = new GaussianBlurEffect();
PropertyCollection bProps = blurEffect.CreatePropertyCollection();
PropertyBasedEffectConfigToken bParameters = new PropertyBasedEffectConfigToken(bProps);
bParameters.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount2);
blurEffect.SetRenderInfo(bParameters, new RenderArgs(dst), new RenderArgs(src));
blurEffect.Render(new Rectangle[1] {rect},0,1);




ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;
ColorBgra cp;	// current pixel
//ColorBgra dp;	// destination pixel
int B, G, R, A, td,ts,lb,lg,lr,la,bb,bg,br,ba,h,w;
	w = 0;h = 0;// needs to be assigned
int th = Amount3;
int H = rect.Bottom - rect.Top;
int W = rect.Right - rect.Left;
int A8 = Amount8;
	int A9 = Amount9;
	//int A10 = Amount10;
bool[,,]v = new bool[W,H,2];	// hope this is ok. array W by H and true or false * 2
bool l = true; bool b = false;	// l = outline = true; b = background = false


	// call load array method
	v = loadarray(src,dst,rect,v,l,b,th);

// call method to reduce isolated pixels
	if(A8 > 0 || A9 > 0){v = altarray(rect,v,l,b,H,W,A8);}


// call thicken lines method
	if(A9 == 1){v = thickenlines(rect,v,l,b,H,W);}






for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 4 - sets BGRA values, re-assembles and sends to dst canvas
	{ for (int x = rect.Left; x < rect.Right; x++) 
	{ 
	h = y - rect.Top;
	w = x - rect.Left;

	cp = src[x,y]; 
	B = (int)cp.B;
	G = (int)cp.G;
	R = (int)cp.R;
	A = (int)cp.A;

	td = (int)dst[x,y].B +(int)dst[x,y].G + (int)dst[x,y].R;// destination - blurred pixel
	ts = B + G + R;// source - unblurred pixel
	lb = 0; lg = 0; lr = 0; la = 255;	// set initial line variables to black
	bb = 255; bg = 255; br = 255; ba = 255;	// set initial background variables to white


	switch (Amount4)// line properties
	{case 0: lb = PrimaryColor.B; lg = PrimaryColor.G; lr = PrimaryColor.R; la = PrimaryColor.A;break;	//line colour = primary colour default black
	case 1: lb = B; lg = G; lr = R;la = 0;break;	//transparent
	case 2: lb = B; lg = G; lr = R; la = A;break;	// as original
	case 3: lb = dst[x,y].B; lg = dst[x,y].G; lr = dst[x,y].R; la = dst[x,y].A;break;	// as blur
	case 4: lb = (int)(ts / 3);lg = (int)(ts / 3);lr = (int)(ts / 3);la = A;break; // src greys
	case 5: lb = (int)(td / 3);lg = (int)(td / 3);lr = (int)(td / 3);la = A;break; // dst greys
	case 6: lb = SecondaryColor.B;lg = SecondaryColor.G;lr = SecondaryColor.R;la = SecondaryColor.A;break;}// secondary colour

	switch (Amount5)//background properties
	{case 0: bb = SecondaryColor.B; bg = SecondaryColor.G; br = SecondaryColor.R; ba = SecondaryColor.A;break;	//background colour = secondary colour default white
	case 1: bb = B; bg = G; br = R; ba = 0;break;	//transparent
	case 2: bb = B; bg = G; br = R; ba = A;break;	// as original
	case 3: bb = dst[x,y].B; bg = dst[x,y].G; br = dst[x,y].R; ba = dst[x,y].A;break;//as blur
	case 4: bb = (int)(ts / 3);bg = (int)(ts / 3);br = (int)(ts / 3);ba = A;break; // src greys
	case 5: bb = (int)(td / 3);bg = (int)(td / 3);br = (int)(td / 3);ba = A;break; // dst greys
	case 6: bb = PrimaryColor.B; bg = PrimaryColor.G; br = PrimaryColor.R; ba = PrimaryColor.A;break;}// primary



	if(v[w,h,1] ==  {B = bb; G = bg; R = br; A = ba;}//background values
	if(v[w,h,1] == l) {B = lb; G = lg; R = lr; A = la;}//outline values
	if(Amount10 == true && v[w,h,0] == l && v[w,h,1] == {B = 255;G = 0; R = 0; A = 255;} // if changed line single pixel make blue
	if(Amount10 == true && v[w,h,0] == b && v[w,h,1] == l){B = 0;G = 0; R = 255; A = 255;} // if changed background single pixel make red




	// re assemble
	cp = ColorBgra.FromBgra( Int32Util.ClampToByte(, Int32Util.ClampToByte(G), Int32Util.ClampToByte(R), Int32Util.ClampToByte(A));
	dst[x,y] = cp;
	}
}
}






















 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

You could use a separate surface and render in OnSetRenderInfo as the code below does.

The result is copied to the ROI after the dstSurface has been rendered.

/* =================================================== */
/* 	*/
/* Newedge.cs 	*/
/* (c) 2011 Red Ochre (John Robbins) 	*/
/* 	*/
/* Description: produces various ink outlines 	*/
/* 	*/
/* ========================================== ======== */

using System;
using System.Text;
using System.Reflection;
using PaintDotNet;
using PaintDotNet.Effects;
using PaintDotNet.IndirectUI;
using PaintDotNet.PropertySystem;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("Newedge")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Red Ochre (John Robbins)")]
[assembly: AssemblyProduct("Newedge")]
[assembly: AssemblyCopyright("Copyright © Red Ochre (John Robbins)")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

namespace TestEffect
{
public class PluginSupportInfo : IPluginSupportInfo
{
	public string Author
	{
	get
	{
	return "Red ochre (John Robbins)";
	}
	}
	public string Copyright
	{
	get
	{
	return ((AssemblyCopyrightAttribute)base.GetType().Assembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false)[0]).Copyright;
	}
	}

	public string DisplayName
	{
	get
	{
	return ((AssemblyProductAttribute)base.GetType().Assembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false)[0]).Product;
	}
	}

	public Version Version
	{
	get
	{
	return base.GetType().Assembly.GetName().Version;
	}
	}

	public Uri WebsiteUri
	{
	get
	{
	return new Uri("http://www.getpaint.net/redirect/plugins.html");
	}
	}
}

[PluginSupportInfo(typeof(PluginSupportInfo), DisplayName = "Newedge")]
public class NewEdgeEffect : PropertyBasedEffect
{
	byte Amount1 = 0; // detection type|0.darker than blur|1.lighter than blur|2.both (blur)
	int Amount2 = 1; // [1,100] blur radius - smoothness OR edge angle OR brush size
	int Amount3 = -150; // [-256,256] dark / bright threshold
	byte Amount4 = 0; // outline properties|primary colour|transparent|as original(src)|as detection type(dst)|src greys|dst greys|secondary colour
	byte Amount5 = 0; // background properties|secondary colour|transparent|as original(src)|as detection type(dst)|src greys|dst greys|primary colour
	int Amount6 = 765; // [0,765] background if tone above this
	int Amount7 = 0; // [0,765] background if tone below this
	int Amount8 = 4; // [0,4] remove isolated pixels
	int Amount9 = 1; // [0,1] thicken lines
	bool Amount10 = true; // [0,1] test: blue = removed, red = added

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

	public static Image StaticIcon
	{
	get
	{
	return null;
	}
	}

	public NewEdgeEffect()
	: base(StaticName, StaticIcon, "Advanced", EffectFlags.Configurable)
	{
	}

	public enum PropertyNames
	{
	Amount1,
	Amount2,
	Amount3,
	Amount4,
	Amount5,
	Amount6,
	Amount7,
	Amount8,
	Amount9,
	Amount10
	}

	public enum Amount1Options
	{
	Amount1Option1,
	Amount1Option2,
	Amount1Option3
	}

	public enum Amount4Options
	{
	Amount4Option1,
	Amount4Option2,
	Amount4Option3,
	Amount4Option4,
	Amount4Option5,
	Amount4Option6,
	Amount4Option7
	}

	public enum Amount5Options
	{
	Amount5Option1,
	Amount5Option2,
	Amount5Option3,
	Amount5Option4,
	Amount5Option5,
	Amount5Option6,
	Amount5Option7
	}


	protected override PropertyCollection OnCreatePropertyCollection()
	{
	List<Property> props = new List<Property>();

	props.Add(StaticListChoiceProperty.CreateForEnum<Amount1Options>(PropertyNames.Amount1, 0, false));
	props.Add(new Int32Property(PropertyNames.Amount2, 1, 1, 100));
	props.Add(new Int32Property(PropertyNames.Amount3, -150, -256, 256));
	props.Add(StaticListChoiceProperty.CreateForEnum<Amount4Options>(PropertyNames.Amount4, 0, false));
	props.Add(StaticListChoiceProperty.CreateForEnum<Amount5Options>(PropertyNames.Amount5, 0, false));
	props.Add(new Int32Property(PropertyNames.Amount6, 765, 0, 765));
	props.Add(new Int32Property(PropertyNames.Amount7, 0, 0, 765));
	props.Add(new Int32Property(PropertyNames.Amount8, 4, 0, 4));
	props.Add(new Int32Property(PropertyNames.Amount9, 1, 0, 1));
	props.Add(new BooleanProperty(PropertyNames.Amount10, true));

	return new PropertyCollection(props);
	}

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

	configUI.SetPropertyControlValue(PropertyNames.Amount1, ControlInfoPropertyNames.DisplayName, "detection type");
	PropertyControlInfo Amount1Control = configUI.FindControlForPropertyName(PropertyNames.Amount1);
	Amount1Control.SetValueDisplayName(Amount1Options.Amount1Option1, "0.darker than blur");
	Amount1Control.SetValueDisplayName(Amount1Options.Amount1Option2, "1.lighter than blur");
	Amount1Control.SetValueDisplayName(Amount1Options.Amount1Option3, "2.both (blur)");
	configUI.SetPropertyControlValue(PropertyNames.Amount2, ControlInfoPropertyNames.DisplayName, "blur radius - smoothness OR edge angle OR brush size");
	configUI.SetPropertyControlValue(PropertyNames.Amount3, ControlInfoPropertyNames.DisplayName, "dark / bright threshold");
	configUI.SetPropertyControlValue(PropertyNames.Amount4, ControlInfoPropertyNames.DisplayName, "outline properties");
	PropertyControlInfo Amount4Control = configUI.FindControlForPropertyName(PropertyNames.Amount4);
	Amount4Control.SetValueDisplayName(Amount4Options.Amount4Option1, "primary colour");
	Amount4Control.SetValueDisplayName(Amount4Options.Amount4Option2, "transparent");
	Amount4Control.SetValueDisplayName(Amount4Options.Amount4Option3, "as original(src)");
	Amount4Control.SetValueDisplayName(Amount4Options.Amount4Option4, "as detection type(dst)");
	Amount4Control.SetValueDisplayName(Amount4Options.Amount4Option5, "src greys");
	Amount4Control.SetValueDisplayName(Amount4Options.Amount4Option6, "dst greys");
	Amount4Control.SetValueDisplayName(Amount4Options.Amount4Option7, "secondary colour");
	configUI.SetPropertyControlValue(PropertyNames.Amount5, ControlInfoPropertyNames.DisplayName, "background properties");
	PropertyControlInfo Amount5Control = configUI.FindControlForPropertyName(PropertyNames.Amount5);
	Amount5Control.SetValueDisplayName(Amount5Options.Amount5Option1, "secondary colour");
	Amount5Control.SetValueDisplayName(Amount5Options.Amount5Option2, "transparent");
	Amount5Control.SetValueDisplayName(Amount5Options.Amount5Option3, "as original(src)");
	Amount5Control.SetValueDisplayName(Amount5Options.Amount5Option4, "as detection type(dst)");
	Amount5Control.SetValueDisplayName(Amount5Options.Amount5Option5, "src greys");
	Amount5Control.SetValueDisplayName(Amount5Options.Amount5Option6, "dst greys");
	Amount5Control.SetValueDisplayName(Amount5Options.Amount5Option7, "primary colour");
	configUI.SetPropertyControlValue(PropertyNames.Amount6, ControlInfoPropertyNames.DisplayName, "background if tone above this");
	configUI.SetPropertyControlValue(PropertyNames.Amount7, ControlInfoPropertyNames.DisplayName, "background if tone below this");
	configUI.SetPropertyControlValue(PropertyNames.Amount8, ControlInfoPropertyNames.DisplayName, "remove isolated pixels");
	configUI.SetPropertyControlValue(PropertyNames.Amount9, ControlInfoPropertyNames.DisplayName, "thicken lines");
	configUI.SetPropertyControlValue(PropertyNames.Amount10, ControlInfoPropertyNames.DisplayName, string.Empty);
	configUI.SetPropertyControlValue(PropertyNames.Amount10, ControlInfoPropertyNames.Description, "test: blue = removed, red = added");

	return configUI;
	}

	private Surface dstSurface;
	GaussianBlurEffect blurEffect = null;
	PropertyCollection bProps = null;
	PropertyBasedEffectConfigToken bParameters = null;
	protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
	{
	this.Amount1 = (byte)((int)newToken.GetProperty<StaticListChoiceProperty>(PropertyNames.Amount1).Value);
	this.Amount2 = newToken.GetProperty<Int32Property>(PropertyNames.Amount2).Value;
	this.Amount3 = newToken.GetProperty<Int32Property>(PropertyNames.Amount3).Value;
	this.Amount4 = (byte)((int)newToken.GetProperty<StaticListChoiceProperty>(PropertyNames.Amount4).Value);
	this.Amount5 = (byte)((int)newToken.GetProperty<StaticListChoiceProperty>(PropertyNames.Amount5).Value);
	this.Amount6 = newToken.GetProperty<Int32Property>(PropertyNames.Amount6).Value;
	this.Amount7 = newToken.GetProperty<Int32Property>(PropertyNames.Amount7).Value;
	this.Amount8 = newToken.GetProperty<Int32Property>(PropertyNames.Amount8).Value;
	this.Amount9 = newToken.GetProperty<Int32Property>(PropertyNames.Amount9).Value;
	this.Amount10 = newToken.GetProperty<BooleanProperty>(PropertyNames.Amount10).Value;

	if (dstSurface == null) // create the new surface
	{
	dstSurface = new Surface(srcArgs.Surface.Size);
	}

	if (blurEffect == null) 
	{
	blurEffect = new GaussianBlurEffect();
	bProps = blurEffect.CreatePropertyCollection();
	bParameters = new PropertyBasedEffectConfigToken(bProps);
	}
	// render to the the temporary surface. 
	this.RenderImage(dstSurface, srcArgs.Surface, dstSurface.Bounds);


	base.OnSetRenderInfo(newToken, dstArgs, srcArgs);
	}


	protected override void OnCustomizeConfigUIWindowProperties(PropertyCollection props)
	{
	// Change the effect's window title
	props[ControlInfoPropertyNames.WindowTitle].Value = "New edge 	Feb 2012 Red Ochre";
	base.OnCustomizeConfigUIWindowProperties(props);
	}

	protected override unsafe void OnRender(Rectangle[] rois, int startIndex, int length)
	{
	if (length == 0) return;
	// copy the result to the destination surface. 
	DstArgs.Surface.CopySurface(dstSurface, rois, startIndex, length); 
	}

	// load array method here
	private unsafe bool[, ,] loadarray(Surface src, Surface dst, Rectangle rect, bool[, ,] v, bool l, bool b, int th)
	{ 	

	for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 1 analyze src and put result in array sval
	{
	ColorBgra* cp = src.GetRowAddressUnchecked(y); 
	ColorBgra* dp = dst.GetRowAddressUnchecked(y);
	for (int x = rect.Left; x < rect.Right; x++)
	{
	int B = (int)cp->B;
	int G = (int)cp->G;
	int R = (int)cp->R;
	int A = (int)cp->A;

	int dB = (int)dp->B;
	int dG = (int)dp->G;
	int dR = (int)dp->R;
	int dA = (int)dp->A;

	int td = dB + dG + dA;// destination - blurred,
	int ts = B + G + R;// source - unblurred pixel


	if (Amount1 == 0 || Amount1 == 2)
	{
	if (ts < td + th && ts > Amount7 && ts <= Amount6) { v[x, y, 0] = l; }	// if darker (line) then true
	else v[x, y, 0] = b;
	}
	if (Amount1 == 1)
	{
	if (ts > td - th && ts > Amount7 && ts <= Amount6) { v[x, y, 0] = l; }	// if lighter than blur by amount2 then also true
	else if (Amount1 == 1) { v[x, y, 0] = b; }
	}
	if (Amount1 == 2)
	{
	if ((ts < td + th || ts >= td - th) && ts > Amount7 && ts <= Amount6) { v[x, y, 0] = l; }// both, if darker (line) or lighter (background)then true
	else if (Amount1 == 2) { v[x, y, 0] = b; }


	}
	v[x, y, 1] = v[x, y, 0];// simply copy initial values to the 2nd part of array

	cp++;
	dp++;
	}
	}// end of loop1



	return v;
	}

	// alter array method here
	private bool[, ,] altarray(Rectangle rect, bool[, ,] v, bool l, bool b, int H, int W, int A8)
	{
	for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 2 - changes sval entries remove single pixels
	{
	for (int x = rect.Left; x < rect.Right; x++)
	{

	int h = y - rect.Top;
	int w = x - rect.Left;

	if ((h >= 1 && h < H - 1)
	&& (w >= 1 && w < W - 1))
	{
	if (A8 >= 1)// case 1 - by 4
	{
	if (v[w, h, 0] == l
	&& v[w - 1, h, 0] == b
	&& v[w, h - 1, 0] == b
	&& v[w, h + 1, 0] == b
	&& v[w + 1, h, 0] == 
	{ v[w, h, 1] = b; }// if line surrounded by 4 background make background
	if (v[w, h, 0] == b
	&& v[w - 1, h, 0] == l
	&& v[w, h - 1, 0] == l
	&& v[w, h + 1, 0] == l
	&& v[w + 1, h, 0] == l)
	{ v[w, h, 1] = l; }// if background surrounded by 4 line make line
	}
	if (A8 >= 2)// case 2 - by 8
	{
	if (v[w, h, 0] == l
	&& v[w - 1, h - 1, 0] == b
	&& v[w - 1, h + 1, 0] == b
	&& v[w + 1, h - 1, 0] == b
	&& v[w + 1, h + 1, 0] == 
	{ v[w, h, 1] = b; }// if line surrounded by 4 background make background
	if (v[w, h, 0] == b
	&& v[w - 1, h - 1, 0] == l
	&& v[w - 1, h + 1, 0] == l
	&& v[w + 1, h - 1, 0] == l
	&& v[w + 1, h + 1, 0] == l)
	{ v[w, h, 1] = l; }// if background surrounded by 4 line make line
	}
	}

	if ((A8 >= 3)
	&& (h >= 2 && h < H - 2)
	&& (w >= 2 && w < W - 2))
	{
	if (v[w, h, 0] == l // case 3 - 20. previous 8 checks & 12 pix perimeter check
	&& v[w - 2, h, 0] == b
	&& v[w - 2, h - 1, 0] == b
	&& v[w - 1, h - 2, 0] == b
	&& v[w, h - 2, 0] == b
	&& v[w + 1, h - 2, 0] == b
	&& v[w + 2, h - 1, 0] == b
	&& v[w + 2, h, 0] == b
	&& v[w + 2, h + 1, 0] == b
	&& v[w + 1, h + 2, 0] == b
	&& v[w, h + 2, 0] == b
	&& v[w - 1, h + 2, 0] == b
	&& v[w - 2, h + 1, 0] == 
	{ v[w, h, 1] = b; } // make background if isolated line pix

	if (v[w, h, 0] == b // case 3 - same for sad lonely background pixies
	&& v[w - 2, h, 0] == l
	&& v[w - 2, h - 1, 0] == l
	&& v[w - 1, h - 2, 0] == l
	&& v[w, h - 2, 0] == l
	&& v[w + 1, h - 2, 0] == l
	&& v[w + 2, h - 1, 0] == l
	&& v[w + 2, h, 0] == l
	&& v[w + 2, h + 1, 0] == l
	&& v[w + 1, h + 2, 0] == l
	&& v[w, h + 2, 0] == l
	&& v[w - 1, h + 2, 0] == l
	&& v[w - 2, h + 1, 0] == l)
	{ v[w, h, 1] = l; } // make line if isolated background pix
	}

	if ((A8 == 4)	// case 4 - 36. previous 20 checks & 16 pix perimeter check
	&& (h >= 3 && h < H - 3)
	&& (w >= 3 && w < W - 3))
	{
	if (v[w, h, 0] == l
	&& v[w - 3, h, 0] == b
	&& v[w - 3, h - 1, 0] == b
	&& v[w - 2, h - 2, 0] == b
	&& v[w - 1, h - 3, 0] == b
	&& v[w, h - 3, 0] == b
	&& v[w + 1, h - 3, 0] == b
	&& v[w + 2, h - 2, 0] == b
	&& v[w + 3, h - 1, 0] == b
	&& v[w + 3, h, 0] == b
	&& v[w + 3, h + 1, 0] == b
	&& v[w + 2, h + 2, 0] == b
	&& v[w + 1, h + 3, 0] == b
	&& v[w, h + 3, 0] == b
	&& v[w - 1, h + 3, 0] == b
	&& v[w - 2, h + 2, 0] == b
	&& v[w - 3, h + 1, 0] == 
	{ v[w, h, 1] = b; } // make background if isolated line pix
	if (v[w, h, 0] == b // case 4 - same for background
	&& v[w - 3, h, 0] == l
	&& v[w - 3, h - 1, 0] == l
	&& v[w - 2, h - 2, 0] == l
	&& v[w - 1, h - 3, 0] == l
	&& v[w, h - 3, 0] == l
	&& v[w + 1, h - 3, 0] == l
	&& v[w + 2, h - 2, 0] == l
	&& v[w + 3, h - 1, 0] == l
	&& v[w + 3, h, 0] == l
	&& v[w + 3, h + 1, 0] == l
	&& v[w + 2, h + 2, 0] == l
	&& v[w + 1, h + 3, 0] == l
	&& v[w, h + 3, 0] == l
	&& v[w - 1, h + 3, 0] == l
	&& v[w - 2, h + 2, 0] == l
	&& v[w - 3, h + 1, 0] == l)
	{ v[w, h, 1] = l; } // make line if isolated background pix
	}
	}
	}
	return v;
	}
	// thicken lines method here
	private bool[, ,] thickenlines(Rectangle rect, bool[, ,] v, bool l, bool b, int H, int W)
	{
	for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 3 - changes array values thickenlines
	{
	for (int x = rect.Left; x < rect.Right; x++)
	{
	int h = y - rect.Top;
	int w = x - rect.Left;

	if ((h >= 1 && h < H - 1)
	&& (w >= 1 && w < W - 1))
	{
	if (v[w, h, 0] == l
	&& v[w, h, 1] == l)
	{
	v[w - 1, h - 1, 1] = l;
	v[w, h - 1, 1] = l;
	v[w + 1, h - 1, 1] = l;
	v[w - 1, h, 1] = l;
	v[w + 1, h, 1] = l;
	v[w - 1, h + 1, 1] = l;
	v[w, h + 1, 1] = l;
	v[w + 1, h + 1, 1] = l;
	}
	}
	}
	}
	return v;
	}



	unsafe void RenderImage(Surface dst, Surface src, Rectangle rect)
	{
	// Call the Gaussian Blur effect 
	bParameters.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount2);
	blurEffect.SetRenderInfo(bParameters, new RenderArgs(dstSurface), new RenderArgs(src));
	blurEffect.Render(new Rectangle[1] { rect }, 0, 1);



	ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
	ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;

	int B, G, R, A, td, ts, lb, lg, lr, la, bb, bg, br, ba, h, w;
	w = 0; h = 0;// needs to be assigned
	int th = Amount3;
	int H = rect.Bottom - rect.Top;
	int W = rect.Right - rect.Left;
	int A8 = Amount8;
	int A9 = Amount9;
	//int A10 = Amount10;
	bool[, ,] v = new bool[W, H, 2];	// hope this is ok. array W by H and true or false * 2
	bool l = true; bool b = false;	// l = outline = true; b = background = false


	// call load array method
	v = loadarray(src, dst, rect, v, l, b, th);

	// call method to reduce isolated pixels
	if (A8 > 0 || A9 > 0) { v = altarray(rect, v, l, b, H, W, A8); }


	// call thicken lines method
	if (A9 == 1) { v = thickenlines(rect, v, l, b, H, W); }

	for (int y = rect.Top; y < rect.Bottom; y++) 	// LOOP 4 - sets BGRA values, re-assembles and sends to dst canvas
	{
	ColorBgra* sp = src.GetRowAddressUnchecked(y);// the pointer to the start of the row 
	ColorBgra* dp = dst.GetRowAddressUnchecked(y);

	for (int x = rect.Left; x < rect.Right; x++)
	{
	h = y - rect.Top;
	w = x - rect.Left;

	B = (int)sp->B;
	G = (int)sp->G;
	R = (int)sp->R;
	A = (int)sp->A;

	td = (int)dp->B + (int)dp->G + (int)dp->R;// destination - blurred pixel
	ts = B + G + R;// source - unblurred pixel
	lb = 0; lg = 0; lr = 0; la = 255;	// set initial line variables to black
	bb = 255; bg = 255; br = 255; ba = 255;	// set initial background variables to white


	switch (Amount4)// line properties
	{
	case 0: lb = PrimaryColor.B; lg = PrimaryColor.G; lr = PrimaryColor.R; la = PrimaryColor.A; break;	//line colour = primary colour default black
	case 1: lb = B; lg = G; lr = R; la = 0; break;	//transparent
	case 2: lb = B; lg = G; lr = R; la = A; break;	// as original
	case 3: lb = dp->B; lg = dp->G; lr = dp->R; la = dp->A; break;	// as blur
	case 4: lb = (int)(ts / 3); lg = (int)(ts / 3); lr = (int)(ts / 3); la = A; break; // src greys
	case 5: lb = (int)(td / 3); lg = (int)(td / 3); lr = (int)(td / 3); la = A; break; // dst greys
	case 6: lb = SecondaryColor.B; lg = SecondaryColor.G; lr = SecondaryColor.R; la = SecondaryColor.A; break;
	}// secondary colour

	switch (Amount5)//background properties
	{
	case 0: bb = SecondaryColor.B; bg = SecondaryColor.G; br = SecondaryColor.R; ba = SecondaryColor.A; break;	//background colour = secondary colour default white
	case 1: bb = B; bg = G; br = R; ba = 0; break;	//transparent
	case 2: bb = B; bg = G; br = R; ba = A; break;	// as original
	case 3: bb = dp->B; bg = dp->G; br = dp->R; ba = dp->A; break;//as blur
	case 4: bb = (int)(ts / 3); bg = (int)(ts / 3); br = (int)(ts / 3); ba = A; break; // src greys
	case 5: bb = (int)(td / 3); bg = (int)(td / 3); br = (int)(td / 3); ba = A; break; // dst greys
	case 6: bb = PrimaryColor.B; bg = PrimaryColor.G; br = PrimaryColor.R; ba = PrimaryColor.A; break;
	}// primary

	if (v[w, h, 1] ==  { B = bb; G = bg; R = br; A = ba; }//background values
	if (v[w, h, 1] == l) { B = lb; G = lg; R = lr; A = la; }//outline values
	if (Amount10 == true && v[w, h, 0] == l && v[w, h, 1] ==  { B = 255; G = 0; R = 0; A = 255; } // if changed line single pixel make blue
	if (Amount10 == true && v[w, h, 0] == b && v[w, h, 1] == l) { B = 0; G = 0; R = 255; A = 255; } // if changed background single pixel make red

	// re assemble
	dp->B = Int32Util.ClampToByte(;
	dp->G = Int32Util.ClampToByte(G);
	dp->R = Int32Util.ClampToByte(R);
	dp->A = Int32Util.ClampToByte(A);

	sp++; // move to the next pixel
	dp++;
	}
	}
	}

}
}

As Visual C# 2010 Express is needed to build it, the compiled dll is attached. :D

NewEdge.zip

  • Upvote 4

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

WOW! - Thank you very, very much :D.

I have visual studio express installed but haven't had much luck with it yet. The code you have supplied above means I have no excuses now!

Again thank you, writing that must have taken an age - I have only just downloaded it but I am sure it will me help immeasurably.

Hopefully this will enable me to explore more complex plugins than are possible with code lab alone. :D

Right - better fire up VS express.

Even more thanks :star: :star: :star: :star: :star::cookie::coffee::)

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

WOW! - Thank you very, very much :D.

I have visual studio express installed but haven't had much luck with it yet. The code you have supplied above means I have no excuses now!

Again thank you, writing that must have taken an age - I have only just downloaded it but I am sure it will me help immeasurably.

Hopefully this will enable me to explore more complex plugins than are possible with code lab alone. :D

Right - better fire up VS express.

Even more thanks :star: :star: :star: :star: :star::cookie::coffee::)

Actually most of the work was understanding the code and updating it to use pointers for faster processing.

The Save as DLL dialog in CodeLab has a View Source checkbox that makes it easy to grab the generated effect code for use in Visual Studio. ;)

If you would like I can PM you the project file.

  • Upvote 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

Yes please - the project file will be useful :).

When I tried using VS express for plugins before, I didn't have much success getting any codelab generated code into it.

Before starting with codelab about a year ago my only coding experience was on the Commodore 64 - nearly 30 years ago!

- so all the 'using' statements and various files needed to create a '.dll' were a bit overwhelming!

The code you have supplied above should help me enormously to get started with VS.

The project file will help a lot too.

It was wonderful to finally see that plugin work without stripes!!!

It is very much a 'beta' regarding the 'enhancements', but once I get the hang of VS, I can work on the algorithms.

Sorry I should have included more explanation comments in the code and more descriptive variable names - but I had all but given up this.

Once again Thank You :star:

File downloaded - brilliant! :)

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

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