Jump to content

Recommended Posts

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:

 

xsjeWlO.png

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 by Reptillian
  • Like 1
  • Upvote 1
Link to post
Share on other sites
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!

 

Link to post
Share on other sites
Posted (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 by Reptillian
Link to post
Share on other sites

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

Xkds4Lh.png

Link to post
Share on other sites
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.

Link to post
Share on other sites
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.

 

Link to post
Share on other sites
Posted (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 by Reptillian
  • Like 1
Link to post
Share on other sites
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 by Reptillian
Link to post
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...