Reptillian 303 Posted January 4 Report Share Posted January 4 (edited) This plugin streaks pixels along an axis. In non-transparent black and white image, it does more than just streaking, it actually calculate distance away to end and insert it into the canvas. There are 2 options here, the direction to streak pixels, and the exponential factor. It's not meant to work with non-transparent rgb image since there are many edge detection algorithm, so that part is left to you if you want to use it on a non-transparent rgb image. It does work with transparent images regardless of whether it's black and white or colored. Output of Effect: This was done by two steps. 1) Edge detect, and then put the output into alpha channel of non-transparent rgb image. 2) Use Axis Streak How to install: Download the zip, and extract it directly into the Effects folder (If you already have GmicSharpNative folder). -> AxisStreakGmicPDN.zip It should be under 'Distort'. It only works for the following: Non-transparent grayscale image (This result in distance mode. The closer to the edge, the darker the pixel are.) Transparent Images It does not work for this case: Non-transparent Colored Image If you don't have 'GmicSharpNativefolder' : Download GMICSharpNative, and extract 'GmicSharpNative' into plugin installation folder named 'Effects'. G'MIC-PDN Plugin Source code: Effects.cs Spoiler using GmicSharpPdn; using PaintDotNet; using PaintDotNet.AppModel; using PaintDotNet.Effects; using PaintDotNet.IndirectUI; using PaintDotNet.PropertySystem; using System.Drawing; using System.Globalization; using System.Reflection; using System.Collections.Generic; namespace Axis_Streak { [PluginSupportInfo(typeof(PluginSupportInfo))] public sealed class AxisStreakGmicPdnPlugin : PropertyBasedEffect { public AxisStreakGmicPdnPlugin() : base("Axis Streak", StaticIcon, SubmenuNames.Distort, new EffectOptions { Flags = EffectFlags.Configurable }) { } public static Image StaticIcon => new Bitmap(typeof(Axis_Streak.AxisStreakGmicPdnPlugin), "AxisStreakIcon.png"); public enum PropertyNames { Val_direction, Val_alp_exp_fact } public enum Val_directionOptions { Up, Down, Left, Right } protected override PropertyCollection OnCreatePropertyCollection() { Property[] props = new Property[] { StaticListChoiceProperty.CreateForEnum<Val_directionOptions>(PropertyNames.Val_direction, 0, false), new DoubleProperty(PropertyNames.Val_alp_exp_fact, 0, -100, 500) }; return new PropertyCollection(props); } protected override ControlInfo OnCreateConfigUI(PropertyCollection props) { ControlInfo configUI = CreateDefaultConfigUI(props); configUI.SetPropertyControlValue(PropertyNames.Val_direction, ControlInfoPropertyNames.DisplayName, "Direction"); configUI.SetPropertyControlType(PropertyNames.Val_direction, PropertyControlType.RadioButton); PropertyControlInfo Val_directionControl = configUI.FindControlForPropertyName(PropertyNames.Val_direction); Val_directionControl.SetValueDisplayName(Val_directionOptions.Up, "Up"); Val_directionControl.SetValueDisplayName(Val_directionOptions.Down, "Down"); Val_directionControl.SetValueDisplayName(Val_directionOptions.Left, "Left"); Val_directionControl.SetValueDisplayName(Val_directionOptions.Right, "Right"); configUI.SetPropertyControlValue(PropertyNames.Val_alp_exp_fact, ControlInfoPropertyNames.DisplayName, "Alpha Exponential Factor (%)"); configUI.SetPropertyControlValue(PropertyNames.Val_alp_exp_fact, ControlInfoPropertyNames.SliderLargeChange, 0.25); configUI.SetPropertyControlValue(PropertyNames.Val_alp_exp_fact, ControlInfoPropertyNames.SliderSmallChange, 0.05); configUI.SetPropertyControlValue(PropertyNames.Val_alp_exp_fact, ControlInfoPropertyNames.UpDownIncrement, 0.01); configUI.SetPropertyControlValue(PropertyNames.Val_alp_exp_fact, ControlInfoPropertyNames.DecimalPlaces, 3); return configUI; } protected override void OnCustomizeConfigUIWindowProperties(PropertyCollection props) { // Add help button to effect UI props[ControlInfoPropertyNames.WindowTitle].Value = "Axis Streak - G'MIC"; props[ControlInfoPropertyNames.WindowHelpContentType].Value = WindowHelpContentType.PlainText; Assembly assembly = typeof(AxisStreakGmicPdnPlugin).Assembly; string fileVersion = assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version; string copyright = assembly.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright; props[ControlInfoPropertyNames.WindowHelpContent].Value = $"Axis_Streak v{ fileVersion }\n\n{ copyright }\nAll rights reserved."; base.OnCustomizeConfigUIWindowProperties(props); } protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs) { int cardinal_direction = (byte)(int)newToken.GetProperty<StaticListChoiceProperty>(PropertyNames.Val_direction).Value; double expf = newToken.GetProperty<DoubleProperty>(PropertyNames.Val_alp_exp_fact).Value / 100; int val_axial_direction = cardinal_direction % 2; bool axial_direction = val_axial_direction == 1; int orientation, direction; if (cardinal_direction < 2) { orientation = 1; if (axial_direction) { direction = 0; } else { direction = 1; } } else { orientation = 0; if (axial_direction) { direction = 1; } else { direction = 0; } } using (PdnGmicSharp gmic = new PdnGmicSharp()) { // Add the source surface as the first input image. using (PdnGmicBitmap source = new PdnGmicBitmap(srcArgs.Surface)) { gmic.AddInputImage(source); } // The following code demonstrates adding an image // from the clipboard as a second G'MIC surface. string command = string.Format(CultureInfo.InvariantCulture, "if s==3 return fi\n" + "if s>1\n" + " vv=0\n" + " repeat s\n" + " sh $>\n" + " vv+={{iv#-1}}\n" + " rm.\n" + " done\n" + " if !$vv break fi\n" + " sh. 0,{{s-2}}\n" + " sh.. {{s}}\n" + " f.. i#-1?I\n" + " /. 255\n" + " if {2}<=-1 exp_f=-{{1-10^-8}} else exp_f={2} fi\n" + " f. i^(1+$exp_f)\n" + " if {0}\n" + " outdata_dim={{w}},1,{{d}},{{s#0}}\n" + " outdata_coords=x,yy\n" + " if {1} direction=yy=hh-1,yy>=0,yy--\n" + " else direction=yy=0,yy<hh,yy++ fi\n" + " else\n" + " outdata_dim=1,{{h}},{{d}},{{s#0}}\n" + " outdata_coords=xx,y\n" + " if {1} direction=xx=0,xx<ww,xx++\n" + " else direction=xx=ww-1,xx>=0,xx-- fi\n" + " fi\n" + " $outdata_dim,\":begin(" + " const ww=w#0;" + " const hh=h#0;" + " );" + " start_val=1;" + " for(\"$direction\"," + " start_val?(" + " start_val=0;" + " col=I(#-2,\"$outdata_coords\");" + " alp=i(#-1,\"$outdata_coords\",z,0);" + " temp=[col,alp];" + " ):(" + " newcol=I(#-2,\"$outdata_coords\");" + " newalp=i(#-1,\"$outdata_coords\",z,0);" + " newinfo=[newcol,newalp];" + " !newalp?(I(#0,\"$outdata_coords\")=temp;):" + " newalp==1?(temp=newinfo;" + " ):(" + " col=newcol*newalp+(1-newalp)*col;" + " alp=alp+newalp*(1-alp);" + " temp=[col,alp];" + " I(#0,\"$outdata_coords\")=temp;" + " );" + " );" + " );\"\n" + " rm[1-3]\n" + " sh. {{s-1}} *. 255 rm.\n" + "else\n" + " sh {{s-1}}\n" + " if !iv#-1 rm. break else rm. fi\n" + " / 255\n" + " if {2}<=-1 exp_f={{1-10^-8}} else exp_f={2} fi\n" + " f i^(1+$exp_f)\n" + " if {0}\n" + " outdata_dim={{w}},1,{{d}},1\n" + " outdata_coords=x,yy\n" + " outdata_dimref=hh\n" + " outdata_pos=yy\n" + " if {1}\n" + " direction=yy=hh,yy>0,yy--\n" + " end_level=yy\n" + " else\n" + " direction=yy=0,yy<hh,yy++\n" + " end_level=(hh-yy)\n" + " fi\n" + " else\n" + " outdata_dim=1,{{h}},{{d}},1\n" + " outdata_coords=xx,y\n" + " outdata_dimref=ww\n" + " outdata_pos=xx\n" + " if {1}\n" + " direction=xx=0,xx<ww,xx++\n" + " end_level=(ww-xx)\n" + " else\n" + " direction=xx=ww,xx>0,xx--\n" + " end_level=xx\n" + " fi\n" + " fi\n" + " $outdata_dim,\"begin(" + " const ww=w#0-1;" + " const hh=h#0-1;" + " );" + " mode=0;" + " for(\"$direction\"," + " imgval=i(#-1,\"$outdata_coords\");" + " !mode?(imgval?mode=1;);" + " mode==1?(z_level=\"$outdata_dimref\";mode=2;alp=imgval;);" + " mode==2?(" + " alp=alp+(1-alp)*imgval;" + " z_level=\"$end_level\"*imgval+(1-imgval)*z_level;" + " i(#-1,\"$outdata_coords\")=\"$end_level\"/z_level*alp;" + " );" + " );\"" + " rm.\n" + " * 255\n" + "fi", orientation.ToString(CultureInfo.InvariantCulture), direction.ToString(CultureInfo.InvariantCulture), expf.ToString(CultureInfo.InvariantCulture)); // Run the G'MIC command and allow it to receive cancellation info from Paint.NET. gmic.RunGmic(command, () => this.IsCancelRequested); if (gmic.Error != null) { this.Services.GetService<IExceptionDialogService>().ShowErrorDialog(null, gmic.Error); } else if (!gmic.Canceled) { Surface output = gmic.OutputImages?[0]?.Surface; if (output != null) { // Copy the rendered G'MIC image to the destination surface, // and restrict the copied portions to the user's selection. dstArgs.Surface.CopySurface(output, this.EnvironmentParameters.GetSelectionAsPdnRegion()); } } } base.OnSetRenderInfo(newToken, dstArgs, srcArgs); } protected override void OnRender(Rectangle[] renderRects, int startIndex, int length) { // All work is performed in OnSetRenderInfo. } } } G'MIC-QT Axis Streak Spoiler #@cli rep_axis_streak: orientation,direction,_alpha_exponential_factor,_maxval>0_cmykmode={ 0=non-cmyk | 1=cmyka_mode } #@cli : Streaks pixels based on distance away from center and placement of visible objects. #@cli : '_alpha_exponential_factor' is used to manipulate the alpha mixing within pixels. The more power that is assigned to the alpha, the more mixing there would be. #@cli : '_maxval' divides the alpha channel internally to normalize ranges to 0-1. A error will appear if not normalized. By default, it used the max alpha channel value. #@cli : '_cmykmode' is only used in case of using only cmyk images. Not needed in normal cases at all. #@cli : Default values: '_alpha_exponential_factor=0','_maxalp=n/a','_cmykmode=0' #@cli : #@cli : Author: Reptorian. rep_axis_streak: skip ${3=0},${4=},${5=0} repeat $! l[$>] if s==1 rep_axis_streak_distance $* else rep_axis_streak_color $* fi endl done #@cli rep_axis_streak_distance: orientation,direction,_alpha_exponential_factor,_maxval #@cli : Extract the alpha, then streaks pixels based on distance away from center and placement of visible objects. #@cli : '_alpha_exponential_factor' is used to manipulate the alpha mixing within pixels. The more power that is assigned to the alpha, the more mixing there would be. #@cli : '_maxval' divides the alpha channel internally to normalize ranges to 0-1. A error will appear if not normalized. By default, it used the max alpha channel value. #@cli : Default values: '_alpha_exponential_factor=0','_maxalp=n/a' #@cli : #@cli : Author: Reptorian. rep_axis_streak_distance: skip ${3=0},${4=} repeat $! l[$>] sh {s-1} if !iv#-1 rm. break else rm. fi if s>1 channels {s-1} fi if narg($4) alp={abs($4)} else alp={iM#-1} fi / $alp if iM>1||im<0 error alpval(valid)==F fi if $3<=-1 exp_f=-{1-10^-8} else exp_f=$3 fi f i^(1+$exp_f) if $1 outdata_dim={w},1,{d},1 outdata_coords=x,yy,z outdata_dimref=hh outdata_pos=yy if $2 direction=yy=hh,yy>0,yy-- end_level=yy else direction=yy=0,yy<hh,yy++ end_level=(hh-yy) fi else outdata_dim=1,{h},{d},1 outdata_coords=xx,y,z outdata_dimref=ww outdata_pos=xx if $2 direction=xx=0,xx<ww,xx++ end_level=(ww-xx) else direction=xx=ww,xx>0,xx-- end_level=xx fi fi $outdata_dim,":begin( const ww=w#0-1; const hh=h#0-1; ); mode=0; for("$direction", imgval=i(#-1,"$outdata_coords"); !mode?(imgval?mode=1;); mode==1?(z_level="$outdata_dimref";mode=2;alp=imgval;); mode==2?( alp=alp+(1-alp)*imgval; z_level="$end_level"*imgval+(1-imgval)*z_level; i(#-1,"$outdata_coords")="$end_level"/z_level*alp; ); );" rm. endl done #@cli rep_axis_streak_color: orientation,direction,_alpha_exponential_factor,_maxval>0_cmykmode={ 0=non-cmyk | 1=cmyka_mode } #@cli : Streaks colored pixels taking into account of opacity. #@cli : '_alpha_exponential_factor' is used to manipulate the alpha mixing within pixels. The more power that is assigned to the alpha, the more mixing there would be. #@cli : '_maxval' divides the alpha channel internally to normalize ranges to 0-1. A error will appear if not normalized. By default, it used the max alpha channel value. #@cli : '_cmykmode' is only used in case of using only cmyk images. Not needed in normal cases at all. #@cli : Default values: '_alpha_exponential_factor=0','_maxalp=n/a','_cmykmode=0' #@cli : #@cli : Author: Reptorian. rep_axis_streak_color: skip ${3=0},${4=},${5=0} tcr=3 if $5 tcr+=1 fi if narg($4) if $4==0 return fi fi repeat $! l[$>] if s==1||s==$tcr break fi vv=0 repeat s sh $> vv+={iv#-1} rm. done if !$vv break fi sh. 0,{s-2} sh.. {s} f.. i#-1?I if narg($4) alp={abs($4)} else alp={iM#-1} fi /. $alp if iM#-1>1||im#-1<0 error alpval(valid)==F fi if $3<=-1 exp_f=-{1-10^-8} else exp_f=$3 fi f. i^(1+$exp_f) if $1 outdata_dim={w},1,{d},{s#0} outdata_coords=x,yy if $2 direction=yy=hh-1,yy>=0,yy-- else direction=yy=0,yy<hh,yy++ fi else outdata_dim=1,{h},{d},{s#0} outdata_coords=xx,y if $2 direction=xx=0,xx<ww,xx++ else direction=xx=ww-1,xx>=0,xx-- fi fi $outdata_dim,":begin( const ww=w#0; const hh=h#0; ); start_val=1; for("$direction", start_val?( start_val=0; col=I(#-2,"$outdata_coords",z); alp=i(#-1,"$outdata_coords",z,0); temp=[col,alp]; ):( newcol=I(#-2,"$outdata_coords",z); newalp=i(#-1,"$outdata_coords",z,0); newinfo=[newcol,newalp]; !newalp?(I(#0,"$outdata_coords",z)=temp;): newalp==1?(temp=newinfo; ):( col=newcol*newalp+(1-newalp)*col; alp=alp+newalp*(1-alp); temp=[col,alp]; I(#0,"$outdata_coords",z)=temp; ); ); );" rm[1-3] sh. {s-1} *. $alp rm. endl done Edited January 5 by Reptillian 1 1 Quote Link to post Share on other sites
sashwilko 497 Posted January 4 Report Share Posted January 4 (edited) 64bit only? Edited January 4 by toe_head2001 removed image Quote Link to post Share on other sites
Reptillian 303 Posted January 4 Author Report Share Posted January 4 (edited) 7 minutes ago, sashwilko said: 64bit only? Yes. I still haven't gotten around the x86, and didn't managed to build it at all via instruction from @null54 Edited January 4 by Reptillian Quote Link to post Share on other sites
lynxster4 3,138 Posted January 5 Report Share Posted January 5 19 hours ago, Reptillian said: This was done by two steps. 1) Edge detect, and then put the output into alpha channel of non-transparent rgb image. 2) Use Axis Streak You may need to explain this. Not everyone is going to understand. Which Edge Detect plugin did you use? I have 2 different ones. I was trying to get it to work on rgb images. Works fine on black & white. Thanks! Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to post Share on other sites
Reptillian 303 Posted January 5 Author Report Share Posted January 5 (edited) 18 minutes ago, lynxster4 said: You may need to explain this. Not everyone is going to understand. Which Edge Detect plugin did you use? I have 2 different ones. I was trying to get it to work on rgb images. Works fine on black & white. Thanks! I used Afre's edge detect in gmic-qt as it result in black and white edge. Then I assigned it to the alpha channel to rgb image. Yes, the rgb image needs to be transparent for the plugin to work. It works in non-transparent black and white because I coded the distance mode for Perspective Streak within G'MIC-QT as it works reasonably well because of less variety along alpha, and hence it is part of the plugin. Making it work with non-transparent rgb is out of scope for the plugin as I would need to add edge detection and insert it into alpha. Edited January 5 by Reptillian Quote Link to post Share on other sites
Djisves 529 Posted January 5 Report Share Posted January 5 @Reptillian, thank you for your time and effort in making plugins for all of us to use. I'm sure I'm just one of many who appreciate your trouble and willingness to offer to the community. So please don't take this the wrong way, but you seem to put a lot of effort into developing and then just not bother how your plugins are received, appreciated or used. You do yourself great dis-justice by not taking the time to write clear and precise instructions for installing your plugins (if the installation is not the standard one - yes, repeat the same "g'mic sharp" instructions for each plugin if necessary), possible limitations, how-to's and examples. Quote Link to post Share on other sites
Reptillian 303 Posted January 5 Author Report Share Posted January 5 30 minutes ago, Djisves said: @Reptillian, thank you for your time and effort in making plugins for all of us to use. I'm sure I'm just one of many who appreciate your trouble and willingness to offer to the community. You're welcome. 30 minutes ago, Djisves said: So please don't take this the wrong way, but you seem to put a lot of effort into developing and then just not bother how your plugins are received, appreciated or used. You do yourself great dis-justice by not taking the time to write clear and precise instructions for installing your plugins (if the installation is not the standard one - yes, repeat the same "g'mic sharp" instructions for each plugin if necessary), possible limitations, how-to's and examples. The thing is that I'm always tired, so all I can honestly do is to leave the plugins out there, and try my best to provide at least the minimum instruction. I just do not want to bother putting more efforts than I want to. I sometime do provide limitation, like in the OP such as it's not intended to work with non-transparent colored image. It can work with transparent images or non-transparent black and white image. Quote Link to post Share on other sites
lynxster4 3,138 Posted January 5 Report Share Posted January 5 4 hours ago, Reptillian said: I used Afre's edge detect in gmic-qt as it result in black and white edge. I did this and got black background with white edges. Good so far. 4 hours ago, Reptillian said: Then I assigned it to the alpha channel to rgb image. Haven't a clue how to do this. Can you explain a little more, please? Thanks. Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to post Share on other sites
Reptillian 303 Posted January 5 Author Report Share Posted January 5 (edited) 19 minutes ago, lynxster4 said: Haven't a clue how to do this. Can you explain a little more, please? Thanks. Full instructions: 1. Duplicate the image into a new layer. 2. Apply afre's edge detect to the duplicate image. 3. Copy the edge detect result into clipboard. 4. Run Alpha Mask into the unaffected layer and have paste from clipboard checkmarked. 5. Run Axis Streak. Alpha Mask plugin here -> Edited January 5 by Reptillian 1 Quote Link to post Share on other sites
lynxster4 3,138 Posted January 5 Report Share Posted January 5 Got it! Thanks @Reptillian 😀 1 Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to post Share on other sites
nitenurse79 690 Posted Monday at 07:31 PM Report Share Posted Monday at 07:31 PM Unable to download GmicSharpNative.zip from the provided link, after clicking on the download I'm prompted with - "This repository has been archived by the owner. It is now read-only" ? Quote Link to post Share on other sites
ardneh 45 Posted Monday at 08:04 PM Report Share Posted Monday at 08:04 PM This may be the same. https://github.com/0xC0000054/gmic-sharp-native/releases/tag/v0.7.0 Quote Link to post Share on other sites
Reptillian 303 Posted Monday at 08:30 PM Author Report Share Posted Monday at 08:30 PM (edited) 59 minutes ago, nitenurse79 said: Unable to download GmicSharpNative.zip from the provided link, after clicking on the download I'm prompted with - "This repository has been archived by the owner. It is now read-only" ? Now, I unarchived it, you should be able to download. I thought people could download it, but that might has to do with me being logged in, so I didn't know. Edited Monday at 08:31 PM by Reptillian Quote Link to post Share on other sites
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.