Jump to content

Axis Streak - 12/02/2021


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

 

Installation steps:

 

Note: Check if you have a folder named 'GmicPDN'. If you already had 'GmicSharpNative', and it was updated after 10/27/2021, then you need to create a new folder called 'GmicPDN', and then drag and drop the GmicPDN effect dlls, and `GmicSharpNative` folder. Otherwise, click on this link -> GmicPDN Download and Instruction.

 

Ensure that the note is taken care of. Then, download the zip, and extract it directly into the Effects folder. ->AxisStreakGmicPdn.zip

 

It's under Object menu.

 

G'MIC-PDN Plugin Source code:

 

Effects.cs

Spoiler
#define USE_CLIPBOARD

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;

#if USE_CLIPBOARD
using PaintDotNet.Clipboard;
#endif

namespace GmicPDNPlugin
{
    [PluginSupportInfo(typeof(PluginSupportInfo))]
    public sealed class GmicPdnPluginEffect : PropertyBasedEffect
    {
        public GmicPdnPluginEffect()
            : base("Axis Streak", StaticIcon, "Object", new EffectOptions { Flags = EffectFlags.Configurable })
        {
        }

        public static Image StaticIcon => new Bitmap(typeof(GmicPDNPlugin.GmicPdnPluginEffect), "Icon.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(GmicPdnPluginEffect).Assembly;

            string fileVersion = assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
            string copyright = assembly.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;

            props[ControlInfoPropertyNames.WindowHelpContent].Value = $"Axis Streak - GmicPDN 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.
        }
    }
}

 

 

PluginSupportInfo.cs

Spoiler
////////////////////////////////////////////////////////////////////////
//
// This file is part of gmic-sharp-pdn-example, an example Paint.NET
// Effect plugin that uses the gmic-sharp-pdn library.
//
// Copyright (c) 2020 Nicholas Hayes
//
// This file is licensed under the MIT License.
// See LICENSE.txt for complete licensing and attribution information.
//
////////////////////////////////////////////////////////////////////////

using PaintDotNet;
using System;
using System.Reflection;

namespace GmicPDNPlugin
{
    public class PluginSupportInfo : IPluginSupportInfo
    {
        private readonly Assembly assembly = typeof(PluginSupportInfo).Assembly;

        public string Author => "Reptorian\nG'MIC# Author : Nicholas Hayes and David Tschumperlé";

        public string Copyright => "Copyright © 2021 Reptorian, Nicholas Hayes and David Tschumperlé";

        public string DisplayName => this.assembly.GetCustomAttribute<AssemblyProductAttribute>().Product;

        public Version Version => this.assembly.GetName().Version;

        public Uri WebsiteUri => new Uri("https://forums.getpaint.net/topic/116417-gmicsharppdn");
    }
}

 

 

AssemblyInfo.cs

 

Spoiler
////////////////////////////////////////////////////////////////////////
//
// This file is part of gmic-sharp-pdn-example, an example Paint.NET
// Effect plugin that uses the gmic-sharp-pdn library.
//
// Copyright (c) 2020 Nicholas Hayes
//
// This file is licensed under the MIT License.
// See LICENSE.txt for complete licensing and attribution information.
//
////////////////////////////////////////////////////////////////////////

using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Superimposes duplicates at a distance, and at equal angles onto canvas.")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Reptorian")]
[assembly: AssemblyProduct("Axis Streak - GmicPDN")]
[assembly: AssemblyCopyright("Copyright © 2021 Reptorian, Nicholas Hayes and David Tschumperlé")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("fbfe3f2e-91cb-40c7-bdd9-aace796d52dc")]

[assembly: SupportedOSPlatform("windows")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.6")]
[assembly: AssemblyFileVersion("1.0.6")]

 

 

EDIT as of 12/01/21: Update into .NET 6.

Edited by Reptillian
  • Like 1
  • Upvote 1

G'MIC Filter Developer

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

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

G'MIC Filter Developer

Link to comment
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 comment
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.

G'MIC Filter Developer

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

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

G'MIC Filter Developer

Link to comment
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

G'MIC Filter Developer

Link to comment
Share on other sites

  • 9 months later...
  • Reptillian changed the title to Axis Streak (Disabled Download - Due to update needed)
  • 1 month later...
  • Reptillian changed the title to Axis Streak - 12/02/2021

Thanks, now I am able to update those two threads.

 

--------

 

For those who arrived, there's a new update to this plugin. Made to be compatible with latest PDN as it's now .NET 6. In addition, it is moved to Object menu.

 

In addition, there been a slight change into installation of g'mic-pdn plugins. Reason being is due to meeting the rule requirement. Please read before download.

G'MIC Filter Developer

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...