Red ochre Posted February 28, 2011 Share Posted February 28, 2011 (edited) 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 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 March 8, 2012 by Red ochre Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
Rick Brewster Posted March 1, 2011 Share Posted March 1, 2011 The rectangles you're given only limit where you can write in the dst image. You can still read from anywhere in the src image. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Red ochre Posted March 1, 2011 Author Share Posted March 1, 2011 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. Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
Red ochre Posted March 9, 2012 Author Share Posted March 9, 2012 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! /* =================================================== */ /* */ /* 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; } } } Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
null54 Posted March 11, 2012 Share Posted March 11, 2012 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. NewEdge.zip 4 Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC | Paint 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 More sharing options...
Red ochre Posted March 11, 2012 Author Share Posted March 11, 2012 WOW! - Thank you very, very much . 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. Right - better fire up VS express. Even more thanks :star: :star: Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
null54 Posted March 12, 2012 Share Posted March 12, 2012 WOW! - Thank you very, very much . 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. Right - better fire up VS express. Even more thanks :star: :star: 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. 1 Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC | Paint 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 More sharing options...
Red ochre Posted March 12, 2012 Author Share Posted March 12, 2012 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 File downloaded - brilliant! Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.