Jump to content

Effects that need an additional surface - any sample code?


Recommended Posts

Does anyone have sample code of an effect that needs to create a scratch surface during processing?

I've been working on an effect for hours with no luck at all. :(

Basically, I need to create a surface and render some stuff to it (based on the source canvas). Then, blur from that scratch surface to the destination surface. Finally, I need to blend the source surface back into the destination surface for presentation of the final effect.

I can provide source if it would help you to understand what I'm trying to do. But, hopefully, someone will have some sample code that I can study.

Thanks!

EDIT: I think that my problem is that the blur starts before the scratch surface is completely finished being created.

If I do all my steps manually, the effect is perfect. If I automate it, there are bands or sometimes no effect at all. The run is not consistant.

Click to play:
j.pngs.pngd.pnga.pngp.png
Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game

Link to comment
Share on other sites

Funny, I edited that into my original post as you were posting... :D

OK, so how do I fix?

I even tried putting some Application.DoEvents() calls in there. It made things better, but never quite consistant.

BTW, Rick once told me that you could do this and said that it was possible to chain effects between the dst canvas and the scratch canvas and back again. But, I just get screwy results.

Click to play:
j.pngs.pngd.pnga.pngp.png
Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game

Link to comment
Share on other sites

No, that shouldn't be a problem. Most of the scratch surface is transparent. Only a few (relatively speaking) pixels are being rendered. And, the Gaussian blur causes those rendered pixels to be fairly transparent. I'm counting on that and that's why I'm blending them back with the source canvas.

Click to play:
j.pngs.pngd.pnga.pngp.png
Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game

Link to comment
Share on other sites

Here is my code:

        protected override unsafe void OnRender(Rectangle[] rois, int startIndex, int length)
       {
           for (int i = startIndex; i             {
               Render2Scratch(DstArgs.Surface, SrcArgs.Surface, rois[i]);
           }
           this.blurEffect.Render(rois, startIndex, length);

           this.NormalOp.Apply(DstArgs.Surface, SrcArgs.Surface, scratch);
       }

It appears that my blurEffect is starting before my Render2Scratch function is done. :(

Click to play:
j.pngs.pngd.pnga.pngp.png
Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game

Link to comment
Share on other sites

OK, here it is:

        protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
       {
           this.Amount1 = newToken.GetProperty(PropertyNames.Amount1).Value;
           this.Amount2 = newToken.GetProperty(PropertyNames.Amount2).Value;

           scratch = new Surface(DstArgs.Size);
           RenderArgs scratchArgs = new RenderArgs(scratch);
           PropertyBasedEffectConfigToken blurToken = new PropertyBasedEffectConfigToken(this.blurProps);
           blurToken.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount1);
           this.blurEffect.SetRenderInfo(blurToken, scratchArgs, dstArgs);

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

Hmmm... I just realized that I'm creating the canvas in there... That can't be good.

Click to play:
j.pngs.pngd.pnga.pngp.png
Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game

Link to comment
Share on other sites

I'm confused by all of this :shock: :) Definitely do NOT call Application.DoEvents() though.

Ever.

Paint.NET v4 will make this sooooo much easier, trust me. (Of course, you want something that works now ...)

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

SetRenderInfo(blurToken, scratchArgs, dstArgs);
You said you need to blur from the scratch to the destination. The pattern for SetRenderInfo is (EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs), so you're passing the destination as the source and the scratch as the destination. Thus, what you rendered to the scratch is overwritten.
Link to comment
Share on other sites

ScriptLab, Film, and Borders N' Shapes all use scratch surfaces.... badly. Here's something better:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using PaintDotNet;
using PaintDotNet.Effects;
using PaintDotNet.PropertySystem;
using PaintDotNet.IndirectUI;

namespace pyrochild.effects.tests
{
   public class ScratchSurfaceTest
       : PropertyBasedEffect
   {
       public static string StaticName
       {
           get
           {
               string s = "scratchsurfacetest";
#if DEBUG
               s += " BETA";
#endif
               return s;
           }
       }

       protected override PropertyCollection OnCreatePropertyCollection()
       {
           return PropertyCollection.CreateEmpty();
       }

       public ScratchSurfaceTest()
           : base(StaticName,
           null,
           null,
           EffectFlags.None)
       {
           gbe = new GaussianBlurEffect();
           nbo = new UserBlendOps.NormalBlendOp();
       }

       GaussianBlurEffect gbe;
       PropertyBasedEffectConfigToken gbeToken; 
       UserBlendOps.NormalBlendOp nbo;

       protected override void OnRender(Rectangle[] rois, int startIndex, int length)
       {
           PdnRegion selection = EnvironmentParameters.GetSelection(SrcArgs.Bounds);

           gbe.Render(rois, startIndex, length);

           //OVERLAY has already been rendered onto DST, so we need to copy SRC *under* it. For that, we need an overload with
           //params for dst, lhs, and rhs, otherwise it assumes we want to put src on top of dst.
           foreach (Rectangle rect in rois)
           {
               Point pt = rect.Location;
               Size sz = rect.Size;
               nbo.Apply(DstArgs.Surface, pt,
                   SrcArgs.Surface, pt,
                   DstArgs.Surface, pt,
                   sz);
           }
       }


       protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
       {
           PdnRegion selection = EnvironmentParameters.GetSelection(srcArgs.Bounds);

           PropertyCollection gbeProps = gbe.CreatePropertyCollection();
           gbeToken = new PropertyBasedEffectConfigToken(gbeProps);
           gbeToken.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, 50);

           //there's room for mem-optimization here, if we want to make the overlay surface only as large
           //as the selection: overlay = new Surface(selection.GetBoundsInt().Size);
           //will take more logic elsewhere, though.
           Surface overlay = new Surface(srcArgs.Size);
           overlay.Clear(selection, ColorBgra.Red);
           RenderArgs oArgs = new RenderArgs(overlay);

           gbe.SetRenderInfo(gbeToken, dstArgs, oArgs);//we want to blur from OVERLAY to DST.

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

Let me know if I need to clarify anything.

xZYt6wl.png

ambigram signature by Kemaru

[i write plugins and stuff]

If you like a post, upvote it!

Link to comment
Share on other sites

Pyrochild helped me out with exactly the same problem when I tried to implement feather control into my "Color to Alpha" plugin (link to original discussion).

Feel free to copy below code (visual studio). It's not cleaned up but has some comments; those marked with "???" are by pyrochild.

Note that I have moved blurring into separate if-block which is ignored until feather token is >0. This is for better performance - because with larger images UI of Color to Alpha becomes quite laggy as soon as feather is on.

using System;
using System.Collections;
using System.Drawing;
using PaintDotNet;
using PaintDotNet.Effects;
using PaintDotNet.PropertySystem;
using System.Collections.Generic;

namespace ColorToAlpha
{
   [EffectCategory(EffectCategory.Adjustment)]
   public class EffectPlugin
       : PaintDotNet.Effects.Effect
   {
       public static string StaticName { get { return "Color to Alpha"; } }

       public static Bitmap StaticImage { get { return new Bitmap(typeof(EffectPlugin), "EffectPluginIcon.png"); } }

       public static string StaticSubMenuName
       {
           get
           {
               return null; // Use for no submenu
               // return "My SubMenu"; // Use for custom submenu
           }
       }

       public EffectPlugin()
           : base(StaticName, StaticImage, StaticSubMenuName, EffectFlags.Configurable)
       {
           blurEffect = new GaussianBlurEffect();
       }

       public override EffectConfigDialog CreateConfigDialog()
       {
           return new ColorToAlpha();
       }

       private GaussianBlurEffect blurEffect;

       PropertyBasedEffectConfigToken blurToken;
       Surface tempSurface;
       RenderArgs temp;
       bool changed;


       protected override void OnSetRenderInfo(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs)
       {
           this.changed = true; 

           EffectPluginConfigToken token = (EffectPluginConfigToken)parameters;

           PropertyCollection blurProps = blurEffect.CreatePropertyCollection();

           blurToken = new PropertyBasedEffectConfigToken(blurProps);
           blurToken.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, token.Feather);
           base.OnSetRenderInfo(parameters, dstArgs, srcArgs);

       }

       public override unsafe void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length)
       {
           EffectPluginConfigToken token = (EffectPluginConfigToken)parameters;
           int feax = token.Feather;
           bool inv = token.Invert;
           int basea = token.BaseAlpha;
           if (feax > 0) // THIS IS FOR FASTER PERFORMANCE WHILE FEATHER IS NOT USED
           {
               PdnRegion selectionRegion = EnvironmentParameters.GetSelection(srcArgs.Bounds);
               if (changed && tempSurface != null) // ??? I set changed = true in OnSetRenderInfo(), to indicate that the user has changed settings and therefore, invalidated our tempSurface. But if it's null it doesn't matter.
               {
                   tempSurface.Dispose(); // ??? Clear up our resource usage. We have to be nice to our user's RAM.
                   tempSurface = null; // ??? Then set it to null so the next ifblock gets executed. I could combine this more elegantly, but the code here evolved organically from the old version, and I'm lazy.
               }
               if (tempSurface == null) // ??? If we don't have a tempSurface at this point (whether it's because we never made one, or just invalidated it above), we need to make one.
               {
                   Rectangle[] gorois = selectionRegion.GetRegionScansInt(); // build new surface "tempSurface"
                   tempSurface = new Surface(srcArgs.Size);
                   temp = new RenderArgs(tempSurface);

                   RenderAlpha(parameters, tempSurface, srcArgs, gorois, 0, gorois.Length);

                   changed = false; // ??? Set changed to false since we've made our tempSurface and it's currently valid, until changed gets set to true again. This prevents us from creating a new overlay every time OnRender() is called

                   blurEffect.SetRenderInfo(blurToken, dstArgs, temp);
               }

               this.blurEffect.Render(rois, startIndex, length);

               for (int i = startIndex; i < startIndex + length; ++i)
               {
                   Rectangle roi = rois[i];

                   for (int y = roi.Top; y < roi.Bottom; ++y)
                   {
                       ColorBgra* dstPtr = dstArgs.Surface.GetPointAddress(roi.X, roi.Y);
                       ColorBgra NewPixel; 
                       ColorBgra OrigPixel;
                       byte a, ro, go, bo, ao, ry, by, gy, ay; // r, g, b,  

                       for (int x = roi.Left; x < roi.Right; ++x)
                       {
                           NewPixel = dstArgs.Surface[x, y]; 
                           //r = NewPixel.R;
                           //g = NewPixel.G;
                           //b = NewPixel.B;
                           a = NewPixel.R; // WE MADE GRAYSCALE IMAGE FROM ALPHA VALUES BEFORE BLURRING (see bottom of RenderAlpha), NOW WE TURN IT BACK TO ALPHA

                           OrigPixel = srcArgs.Surface[x, y];
                           ro = OrigPixel.R;
                           go = OrigPixel.G;
                           bo = OrigPixel.B;
                           ao = OrigPixel.A;

                           byte baseab = (byte)basea;
                           if (baseab > 0 && a < baseab) 
                           a = baseab;

                           // INVERT
                           if (inv == true)
                               a = (byte)(255 - a);

                           if (selectionRegion.IsVisible(x, y))
                           {
                               ry = Utility.ClampToByte(ro);
                               gy = Utility.ClampToByte(go);
                               by = Utility.ClampToByte(bo);
                               ay = Utility.ClampToByte(a);
                               NewPixel = ColorBgra.FromBgra(by, gy, ry, ay);

                               *dstPtr = NewPixel;
                               ++dstPtr;
                           }
                       }
                   }
               }
           }

           else // feather token = 0; no need for 3rd surface rendering
           {
               int hue1 = token.huefrom;
               int hue2 = token.hueto;
               int sat1 = token.satfrom;
               int sat2 = token.satto;
               int b1 = token.bnessfrom;
               int b2 = token.bnessto;
               int tol = token.Tolerance;
               bool huebox = token.Huebox;
               bool satbox = token.Satbox;
               bool bnessbox = token.Bnessbox;
               bool ovrride = token.Ovrride; // NEW

               for (int i = startIndex; i < startIndex + length; ++i)
               {
                   Rectangle roi = rois[i];

                   for (int y = roi.Top; y < roi.Bottom; ++y)
                   {
                       ColorBgra* srcPtr = srcArgs.Surface.GetPointAddress(roi.X, roi.Y);
                       ColorBgra* dstPtr = dstArgs.Surface.GetPointAddress(roi.X, roi.Y);
                       ColorBgra CurrentPixel;
                       ColorBgra OrigPixel;
                       byte ro, go, bo, ao, ry, by, gy, ay; // r, g, b, a, 
                       float amtx;
                       double ax, huej, huel, satj, satl, brtj, brtl, huej1, huel1, huej0, huel0, satj1, satl1, brtj1, brtl1, fn, ft, fu, fv, ffn, fft, ffu, ffv, fxx;

                       for (int x = roi.Left; x < roi.Right; ++x)
                       {
                           OrigPixel = srcArgs.Surface[x, y];
                           ro = OrigPixel.R;
                           go = OrigPixel.G;
                           bo = OrigPixel.B;
                           ao = OrigPixel.A;
                           amtx = 1 - basea / 255f; 

                           CurrentPixel = dstArgs.Surface[x, y];

                           // GET HUE: FROM UnaryPixelOps.cs:
                           HsvColor hsvColor = HsvColor.FromColor(OrigPixel.ToColor());
                           int hue = hsvColor.Hue;
                           int satur = hsvColor.Saturation;
                           int brt = (int)OrigPixel.GetIntensityByte();

                           if (hue1 > 359)
                               hue1 = 359;
                           if (hue2 > 359)
                               hue2 = 359;

                           double huearea = (hue2 - hue1);
                           if (hue2 < hue1)
                               huearea += 360;

                           double hfea = tol;
                           if (tol > ((360 - huearea) / 2) * 255 / 360)
                               hfea = ((360 - huearea) / 2) * 255 / 360; // adjust hue fading to avoid crossing over total 360


                           // virtually shift hue into "normal" min-max bounds in case hue_from > hue_to
                           double nhue0 = -(hue2 - hue1);
                           double nhue1 = (((nhue0 + Math.Abs(nhue0)) / 2) / 360);
                           double nhuex = (Math.Ceiling(nhue1)); // return 1 if hue_from > hue_to; else 0
                           int nhue = (int)((360 - hue1) * nhuex);
                           int huex = hue;
                           huex += nhue;
                           while (huex > 359)
                           {
                               huex -= 360;
                           }

                           double hue22 = 360 - hue1;
                           double hue12 = 360 - hue2;
                           double huez = 360 - hue;

                           // hue limiter *while hue_from > hue_to*
                           huej = (hue2 + nhue - huex + 1 - 0.1); // huej = (hue2 + nhue - huex + 1 - 0.1);
                           huel = (((huej + Math.Abs(huej)) / 2) / huej); // hue_to limiter

                           // hue limiters *while hue_from < hue_to*
                           huej0 = ((hue2 - hue + 1 - 0.1) * (1 - nhuex)) + ((hue22 - huez + 1 - 0.1) * nhuex);
                           huel0 = (((huej0 + Math.Abs(huej0)) / 2) / huej0); // hue_to limiter
                           huej1 = ((hue - hue1 + 1 - 0.1) * (1 - nhuex)) + ((huez - hue12 + 1 - 0.1) * nhuex);
                           huel1 = (((huej1 + Math.Abs(huej1)) / 2) / huej1);// hue_from limiter


                           double huelx = (huel * nhuex + huel0 * huel1 * (1 - nhuex)); // use only one set of limiters from cases hue_from > hue_to OR hue_from < hue_to

                           satj = (sat2 - satur + 1 - 0.1);
                           satl = (((satj + Math.Abs(satj)) / 2) / satj); // saturation_to limiter
                           satj1 = (satur - sat1 + 1 - 0.1);
                           satl1 = (((satj1 + Math.Abs(satj1)) / 2) / satj1); // saturation_from limiter

                           brtj = (b2 - brt + 1 - 0.1);
                           brtl = (((brtj + Math.Abs(brtj)) / 2) / brtj); // brightness_to limiter
                           brtj1 = (brt - b1 + 1 - 0.1);
                           brtl1 = (((brtj1 + Math.Abs(brtj1)) / 2) / brtj1); // brightness_from limiter

                           double ax0 = (huelx * satl * brtl * satl1 * brtl1);
                           double ax1 = ((1 - ax0) * (1 - amtx) + ax0); // set alpha of non-picked pixels to inverse of amount

                           double ax0h = huelx; // double ax0h = (satl * brtl * satl1 * brtl1);
                           double ax1h = ((1 - ax0h) * (1 - amtx) + ax0h); // set alpha of non-picked pixels to inverse of amount

                           double ax0s = (satl * satl1); // double ax0s = (huelx * brtl * brtl1);
                           double ax1s = ((1 - ax0s) * (1 - amtx) + ax0s); // set alpha of non-picked pixels to inverse of amount

                           double ax0b = (brtl * brtl1); // double ax0b = (huelx * satl * satl1);
                           double ax1b = ((1 - ax0b) * (1 - amtx) + ax0b); //  set alpha of non-picked pixels to inverse of amount


                           // HUE FADING TO_LIMITER
                           double huej0f = (huej0 * 255 / 360);
                           if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 359) // XXXX TEST if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 360)
                               huej0f = ((huej0 - 1 + 0.1 - 360) * 255 / 360); // XXX TEST huej0f = ((huej0 - 1 + 0.1 - 361) * 255 / 360); 
                           if (huej0 - 1 + 0.1 + (hfea * 360 / 255) < 0) // XXXX TEST if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 360)
                               huej0f = ((huej0 - 1 + 0.1 + 360) * 255 / 360); // XXX TEST huej0f = ((huej0 - 1 + 0.1 - 361) * 255 / 360); 

                           fn = (((-huej0f + Math.Abs(-huej0f)) / 2) / -huej0f); //  * ax1h;
                           ft = (-huej0f / (hfea + 0.01)); // tol -> hfea
                           fu = (1 - ft * amtx);
                           fv = (fu * fn + ax0h * (1 - fn)); //(fu * fn * fo + ax1 * fm + ax1 * (1 - fn)); // 

                           // HUE FADING FROM_LIMITER
                           double huej1f = (huej1 * 255 / 360);
                           if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 359) //XXXX if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 360)
                               huej1f = ((huej1 - 1 + 0.1 - 360) * 255 / 360); // XXX huej1f = ((huej1 - 1 + 0.1 - 361) * 255 / 360); 
                           if (huej1 - 1 + 0.1 + (hfea * 360 / 255) < 0) //XXXX if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 360)
                               huej1f = ((huej1 - 1 + 0.1 + 360) * 255 / 360); // XXX huej1f = ((huej1 - 1 + 0.1 - 361) * 255 / 360); 

                           ffn = (((-huej1f + Math.Abs(-huej1f)) / 2) / -huej1f); //  *ax1h;
                           fft = (-huej1f / (hfea + 0.01)); // tol -> hfea
                           ffu = (1 - fft * amtx);
                           ffv = (ffu * ffn + ax0h * (1 - ffn)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // 
                           fxx = (Math.Max(fv, ffv)); // HUE TO ALPHA MULTIPLIER
                           if (huebox == false)
                               fxx = 1; // fxx = ax1h; // 

                           // SATURATION FADING TO_LIMITER
                           double satjf = (satj * 255 / 100); //  * ax1 ei sobi siia
                           double fns = (((-satjf + Math.Abs(-satjf)) / 2) / -satjf); //  * ax1s;
                           double fts = (-satjf / (tol + 0.01)); // tol -> hfea
                           double fus = (1 - fts * amtx);
                           double fvs = (fus * fns + ax0s * (1 - fns)); //double fvs = (fus * fns + ax1 * (1 - fns));

                           // SATURATION FADING FROM_LIMITER
                           double satj1f = (satj1 * 255 / 100); //  * ax1 ei sobi siia
                           double ffns = (((-satj1f + Math.Abs(-satj1f)) / 2) / -satj1f); //  * ax1s;
                           double ffts = (-satj1f / (tol + 0.01)); // tol -> hfea
                           double ffus = (1 - ffts * amtx);
                           double ffvs = (ffus * ffns + ax0s * (1 - ffns)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // 
                           double fxxs = (Math.Max(fvs, ffvs)) * fxx; // SATURATION+HUE TO ALPHA MULTIPLIER
                           if (satbox == false)
                               fxxs = fxx; // fxxs = ax1s * fxx; // 


                           // BRIGHTNESS FADING TO_LIMITER
                           double fnb = (((-brtj + Math.Abs(-brtj)) / 2) / -brtj); //  * ax1b;
                           double ftb = (-brtj / (tol + 0.01)); // tol -> hfea
                           double fub = (1 - ftb * amtx);
                           double fvb = (fub * fnb + ax0b * (1 - fnb)); //(fu * fn * fo + ax1 * fm + ax1 * (1 - fn)); // 

                           // BRIGHTNESS FADING FROM_LIMITER
                           double ffnb = (((-brtj1 + Math.Abs(-brtj1)) / 2) / -brtj1); //  * ax1b;
                           double fftb = (-brtj1 / (tol + 0.01)); // tol -> hfea
                           double ffub = (1 - fftb * amtx);
                           double ffvb = (ffub * ffnb + ax0b * (1 - ffnb)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // 
                           double fxxb = (Math.Max(fvb, ffvb)) * fxxs; // BRIGHTNESS+HUE+SATURATION TO ALPHA MULTIPLIER
                           if (bnessbox == false)
                               fxxb = fxxs; // fxxb = ax1b * fxxs;// 


                           // even out alpha for non-selected areas
                           double fxxx0 = Math.Ceiling(fxxb);
                           double fxxx = fxxb + (1 - amtx) * (1 - fxxx0);

                           if (fxxx < (1 - amtx))
                               fxxx = (1 - amtx);

                           if (ovrride == true) // NEW
                               ao = 255;

                           ax = (ao * fxxx); // FINAL ALPHA

                           byte baseab = (byte)basea;
                           if (baseab > 0 && ax < baseab) // REVISED 21-01-08
                               ax = baseab;

                           // invert
                           if (inv == true)
                               ax = (255 - ax);


                           ry = Utility.ClampToByte(ro);
                           gy = Utility.ClampToByte(go);
                           by = Utility.ClampToByte(bo);
                           ay = Utility.ClampToByte(ax);
                           CurrentPixel = ColorBgra.FromBgra(by, gy, ry, ay); 

                           *dstPtr = CurrentPixel;
                           ++dstPtr;

                       }
                   }
               }
           }
       }


       private unsafe void RenderAlpha(EffectConfigToken parameters, Surface surface, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length)
       {
           EffectPluginConfigToken token = (EffectPluginConfigToken)parameters;

           int hue1 = token.huefrom;
           int hue2 = token.hueto;
           int sat1 = token.satfrom;
           int sat2 = token.satto;
           int b1 = token.bnessfrom;
           int b2 = token.bnessto;
           int tol = token.Tolerance;
           int basea = token.BaseAlpha; 
           basea += 1; // HEAL THE SHIFT IN RESULTS
           bool huebox = token.Huebox;
           bool satbox = token.Satbox;
           bool bnessbox = token.Bnessbox;
           bool ovrride = token.Ovrride; 

           for (int i = startIndex; i < startIndex + length; ++i)
           {
               Rectangle roi = rois[i];

               for (int y = roi.Top; y < roi.Bottom; ++y)
               {
                   ColorBgra* ptr = surface.GetPointAddressUnchecked(roi.Left, y); 
                   ColorBgra OrigPixel;
                   byte ro, go, bo, ao, ry, by, gy, ay; // r, g, b, a, 
                   float amtx;
                   double ax, huej, huel, satj, satl, brtj, brtl, huej1, huel1, huej0, huel0, satj1, satl1, brtj1, brtl1, fn, ft, fu, fv, ffn, fft, ffu, ffv, fxx;

                   for (int x = roi.Left; x < roi.Right; ++x)
                   {
                       OrigPixel = srcArgs.Surface[x, y];
                       ro = OrigPixel.R;
                       go = OrigPixel.G;
                       bo = OrigPixel.B;
                       ao = OrigPixel.A;
                       amtx = 1 - basea / 255f; // amtx = amt / 100f;

                       // GET HUE: FROM UnaryPixelOps.cs:
                       HsvColor hsvColor = HsvColor.FromColor(OrigPixel.ToColor());
                       int hue = hsvColor.Hue;
                       int satur = hsvColor.Saturation;
                       int brt = (int)OrigPixel.GetIntensityByte();

                       if (hue1 > 359)
                           hue1 = 359;
                       if (hue2 > 359)
                           hue2 = 359;

                       double huearea = (hue2 - hue1);
                       if (hue2 < hue1)
                           huearea += 360;

                       double hfea = tol;
                       if (tol > ((360 - huearea) / 2) * 255 / 360)
                           hfea = ((360 - huearea) / 2) * 255 / 360; // adjust hue fading to avoid crossing over total 360


                       // virtually shift hue into "normal" min-max bounds in case hue_from > hue_to
                       double nhue0 = -(hue2 - hue1);
                       double nhue1 = (((nhue0 + Math.Abs(nhue0)) / 2) / 360);
                       double nhuex = (Math.Ceiling(nhue1)); // return 1 if hue_from > hue_to; else 0
                       int nhue = (int)((360 - hue1) * nhuex);
                       int huex = hue;
                       huex += nhue;
                       while (huex > 359)
                       {
                           huex -= 360;
                       }

                       double hue22 = 360 - hue1;
                       double hue12 = 360 - hue2;
                       double huez = 360 - hue;

                       // hue limiter *while hue_from > hue_to*
                       huej = (hue2 + nhue - huex + 1 - 0.1); // huej = (hue2 + nhue - huex + 1 - 0.1);
                       huel = (((huej + Math.Abs(huej)) / 2) / huej); // hue_to limiter

                       // hue limiters *while hue_from < hue_to*
                       huej0 = ((hue2 - hue + 1 - 0.1) * (1 - nhuex)) + ((hue22 - huez + 1 - 0.1) * nhuex);
                       huel0 = (((huej0 + Math.Abs(huej0)) / 2) / huej0); // hue_to limiter
                       huej1 = ((hue - hue1 + 1 - 0.1) * (1 - nhuex)) + ((huez - hue12 + 1 - 0.1) * nhuex);
                       huel1 = (((huej1 + Math.Abs(huej1)) / 2) / huej1);// hue_from limiter


                       double huelx = (huel * nhuex + huel0 * huel1 * (1 - nhuex)); // use only one set of limiters from cases hue_from > hue_to OR hue_from < hue_to

                       satj = (sat2 - satur + 1 - 0.1);
                       satl = (((satj + Math.Abs(satj)) / 2) / satj); // saturation_to limiter
                       satj1 = (satur - sat1 + 1 - 0.1);
                       satl1 = (((satj1 + Math.Abs(satj1)) / 2) / satj1); // saturation_from limiter

                       brtj = (b2 - brt + 1 - 0.1);
                       brtl = (((brtj + Math.Abs(brtj)) / 2) / brtj); // brightness_to limiter
                       brtj1 = (brt - b1 + 1 - 0.1);
                       brtl1 = (((brtj1 + Math.Abs(brtj1)) / 2) / brtj1); // brightness_from limiter

                       double ax0 = (huelx * satl * brtl * satl1 * brtl1);
                       double ax1 = ((1 - ax0) * (1 - amtx) + ax0); // set alpha of non-picked pixels to inverse of amount

                       double ax0h = huelx; // double ax0h = (satl * brtl * satl1 * brtl1);
                       double ax1h = ((1 - ax0h) * (1 - amtx) + ax0h); // set alpha of non-picked pixels to inverse of amount

                       double ax0s = (satl * satl1); // double ax0s = (huelx * brtl * brtl1);
                       double ax1s = ((1 - ax0s) * (1 - amtx) + ax0s); // set alpha of non-picked pixels to inverse of amount

                       double ax0b = (brtl * brtl1); // double ax0b = (huelx * satl * satl1);
                       double ax1b = ((1 - ax0b) * (1 - amtx) + ax0b); // set alpha of non-picked pixels to inverse of amount



                       // HUE FADING TO_LIMITER
                       double huej0f = (huej0 * 255 / 360);
                       if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 359) // XXXX TEST if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 360)
                           huej0f = ((huej0 - 1 + 0.1 - 360) * 255 / 360); // XXX TEST huej0f = ((huej0 - 1 + 0.1 - 361) * 255 / 360); 
                       if (huej0 - 1 + 0.1 + (hfea * 360 / 255) < 0) // XXXX TEST if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 360)
                           huej0f = ((huej0 - 1 + 0.1 + 360) * 255 / 360); // XXX TEST huej0f = ((huej0 - 1 + 0.1 - 361) * 255 / 360); 

                       fn = (((-huej0f + Math.Abs(-huej0f)) / 2) / -huej0f); //  * ax1h;
                       ft = (-huej0f / (hfea + 0.01)); // tol -> hfea
                       fu = (1 - ft * amtx);
                       fv = (fu * fn + ax0h * (1 - fn)); //(fu * fn * fo + ax1 * fm + ax1 * (1 - fn)); // 

                       // HUE FADING FROM_LIMITER
                       double huej1f = (huej1 * 255 / 360);
                       if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 359) //XXXX if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 360)
                           huej1f = ((huej1 - 1 + 0.1 - 360) * 255 / 360); // XXX huej1f = ((huej1 - 1 + 0.1 - 361) * 255 / 360); 
                       if (huej1 - 1 + 0.1 + (hfea * 360 / 255) < 0) //XXXX if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 360)
                           huej1f = ((huej1 - 1 + 0.1 + 360) * 255 / 360); // XXX huej1f = ((huej1 - 1 + 0.1 - 361) * 255 / 360); 

                       ffn = (((-huej1f + Math.Abs(-huej1f)) / 2) / -huej1f); //  *ax1h;
                       fft = (-huej1f / (hfea + 0.01)); // tol -> hfea
                       ffu = (1 - fft * amtx);
                       ffv = (ffu * ffn + ax0h * (1 - ffn)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // 
                       fxx = (Math.Max(fv, ffv)); // HUE TO ALPHA MULTIPLIER
                       if (huebox == false)
                           fxx = 1; // fxx = ax1h; // 

                       // SATURATION FADING TO_LIMITER
                       double satjf = (satj * 255 / 100); //  * ax1 ei sobi siia
                       double fns = (((-satjf + Math.Abs(-satjf)) / 2) / -satjf); //  * ax1s;
                       double fts = (-satjf / (tol + 0.01)); // tol -> hfea
                       double fus = (1 - fts * amtx);
                       double fvs = (fus * fns + ax0s * (1 - fns)); //double fvs = (fus * fns + ax1 * (1 - fns));

                       // SATURATION FADING FROM_LIMITER
                       double satj1f = (satj1 * 255 / 100); //  * ax1 ei sobi siia
                       double ffns = (((-satj1f + Math.Abs(-satj1f)) / 2) / -satj1f); //  * ax1s;
                       double ffts = (-satj1f / (tol + 0.01)); // tol -> hfea
                       double ffus = (1 - ffts * amtx);
                       double ffvs = (ffus * ffns + ax0s * (1 - ffns)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // 
                       double fxxs = (Math.Max(fvs, ffvs)) * fxx; // SATURATION+HUE TO ALPHA MULTIPLIER
                       if (satbox == false)
                           fxxs = fxx; // fxxs = ax1s * fxx; // 


                       // BRIGHTNESS FADING TO_LIMITER
                       double fnb = (((-brtj + Math.Abs(-brtj)) / 2) / -brtj); //  * ax1b;
                       double ftb = (-brtj / (tol + 0.01)); // tol -> hfea
                       double fub = (1 - ftb * amtx);
                       double fvb = (fub * fnb + ax0b * (1 - fnb)); //(fu * fn * fo + ax1 * fm + ax1 * (1 - fn)); // 

                       // BRIGHTNESS FADING FROM_LIMITER
                       double ffnb = (((-brtj1 + Math.Abs(-brtj1)) / 2) / -brtj1); //  * ax1b;
                       double fftb = (-brtj1 / (tol + 0.01)); // tol -> hfea
                       double ffub = (1 - fftb * amtx);
                       double ffvb = (ffub * ffnb + ax0b * (1 - ffnb)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // 
                       double fxxb = (Math.Max(fvb, ffvb)) * fxxs; // BRIGHTNESS+HUE+SATURATION TO ALPHA MULTIPLIER
                       if (bnessbox == false)
                           fxxb = fxxs; // fxxb = ax1b * fxxs;// 

                       // even out alpha for non-selected areas
                       double fxxx0 = Math.Ceiling(fxxb);
                       double fxxx = fxxb + (1 - amtx) * (1 - fxxx0);

                       if (fxxx < (1 - amtx))
                           fxxx = (1 - amtx);

                       if (ovrride == true) // NEW
                           ao = 255;

                       ax = (ao * fxxx); // FINAL ALPHA

                       // TRICK TO BYPASS GAUSSIAN BLUR MISBEHAVIOUR ON SEMITRANSPARENT PIXELS (BUG IN PDN 3.22)
                       // TYPE OF BUG: ALPHA (and Value) OF SEMITRANSPARENT PIXELS IS REDUCED
                       // WE MAKE GRAYSCALE IMAGE WITH NO TRANSPARENCY, BASED ON ALPHA VALUES
                       // THEN WE BLUR THIS (CALLED FROM MAIN RENDER) WITHOUT MISTAKES AND TURN RESULT BACK TO ALPHA VALUES
                       ry = Utility.ClampToByte(ax);
                       gy = Utility.ClampToByte(ax);
                       by = Utility.ClampToByte(ax);
                       ay = Utility.ClampToByte(255);
                       OrigPixel = ColorBgra.FromBgra(by, gy, ry, ay); 

                       *ptr = OrigPixel;
                       ++ptr;

                   }
               }
           }
       }


   }
}

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