Sign in to follow this  
BoltBait

Hue / Saturation Plus - for v4.0

Recommended Posts

Hue / Saturation Plus

This plugin is for Paint.NET 4.0+ only. It will not work on v3.5.11 or below, sorry.

NOTE:

User evanolds has made a more feature rich version of this plugin.*
I am releasing this as a demonstration for how to add slider decorations to 4.0 plugins.**

*evanolds plugin can be found here: http://forums.getpaint.net/index.php?/topic/13003-a

**Read the tutorial here: http://forums.getpaint.net/index.php?/topic/28423-a

 

That said, here's what it looks like:

HueSatPlusUI.png

Download

Users can download here:

BoltBait's Plugin Pack for Paint.NET v4.0+

I think the best way to get used to how this effect works is to play with this using a picture of a color wheel. That way you'll see how the condition works. The adjustments work exactly the same as the built-in Hue / Saturation effect.

 


Programmer's Section


 

Programmers can download the CodeLab script here:

Spoiler

// Title: BoltBait's Hue / Saturation Plus v4.1
// Name: Hue / Saturation Plus
// Submenu: Photo
// URL: http://boltbait.com/pdn/
// Author: BoltBait
// Version: 4.1
// Desc: Conditional Hue/Saturation Adjustment
// Keywords: Conditional|Hue|Saturation|Adjustment
#region UICode
IntSliderControl Amount1 = 0; // [0,360,1] {!Amount10} From Hue
IntSliderControl Amount2 = 360; // [0,360,1] {!Amount10} To Hue
CheckboxControl Amount3 = false; // [0,1] {!Amount10} Also select gray pixels
IntSliderControl Amount4 = 0; // [0,100,3] {!Amount10} From Saturation
IntSliderControl Amount5 = 100; // [0,100,3] {!Amount10} To Saturation
IntSliderControl Amount6 = 0; // [-180,180,2] {!Amount10} Hue Adjustment
IntSliderControl Amount7 = 0; // [-100,100,3] {!Amount10} Saturation Adjustment
IntSliderControl Amount8 = 0; // [-100,100,5] {!Amount10} Lightness Adjustment
IntSliderControl Amount9 = 0; // [-100,100,5] {!Amount10} Alpha Adjustment
CheckboxControl Amount10 = false; // [0,1] Preview original image
#endregion

int loc = -1;

byte Clamp2Byte(double Value)
{
    if (Value > 255) return 255;
    if (Value < 0) return 0;
    return (byte)Value;
}

private UnaryPixelOps.HueSaturationLightness saturationOp;
private UnaryPixelOps.HueSaturationLightness graySatOp;

unsafe void Render(Surface dst, Surface src, Rectangle rect)
{
    if (Amount10)
    {
        dst.CopySurface(src, rect.Location, rect);
        return;
    }
    bool GrayCond = Amount3;
    int FromHue = Amount1;
    int ToHue = Amount2;
    bool ReverseHueCond = false;
    int FromSat = Amount4;
    int ToSat = Amount5;
    bool ReverseSatCond = false;
    if (FromHue > ToHue)
    {
        int TempHue = FromHue;
        FromHue = ToHue;
        ToHue = TempHue;
        ReverseHueCond = true;
    }
    if (FromSat > ToSat)
    {
        int TempSat = FromSat;
        FromSat = ToSat;
        ToSat = TempSat;
        ReverseSatCond = true;
    }

    saturationOp = new UnaryPixelOps.HueSaturationLightness(Amount6, Amount7+100, Amount8);
    graySatOp = new UnaryPixelOps.HueSaturationLightness(0, 100, Amount8);

    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        ColorBgra* srcPtr = src.GetPointAddressUnchecked(rect.Left, y);
        ColorBgra* dstPtr = dst.GetPointAddressUnchecked(rect.Left, y);
        for (int x = rect.Left; x < rect.Right; x++)
        {
            ColorBgra CurrentPixel = *srcPtr;
            byte R = CurrentPixel.R;
            byte G = CurrentPixel.G;
            byte B = CurrentPixel.B;
            int K = (int)((double)CurrentPixel.R / 255d * 100d);
            HsvColor hsv = HsvColor.FromColor(CurrentPixel.ToColor());
            int H = hsv.Hue;
            int S = hsv.Saturation;
            int V = hsv.Value;
            byte A = CurrentPixel.A;

            // Adjust only if not gray
            if (R != G || R != B || G != B)
            {
                if (CurrentPixel.A > 0)
                {
                    // Check if we're in selected Hue range
                    if ((H >= FromHue && H <= ToHue) != ReverseHueCond)
                    {
                        // and selected saturation range
                        if ((S >= FromSat && S <= ToSat) != ReverseSatCond)
                        {
                            // adjust the pixel
                            CurrentPixel = saturationOp.Apply(CurrentPixel);
                            // adjust pixel alpha
                            if (Amount9 < 0)
                            {
                                CurrentPixel.A = Clamp2Byte((double)CurrentPixel.A + ((double)CurrentPixel.A * ((double)Amount9 / 100.0)));
                            }
                            else if (Amount9 > 0)
                            {
                                CurrentPixel.A = Clamp2Byte((double)CurrentPixel.A + (((255 - (double)CurrentPixel.A) * (double)Amount9 / 100.0)));
                            }
                        }
                    }
                }
            }
            else
            {
                if (CurrentPixel.A > 0)
                {
                    // Adjust if gray
                    if (GrayCond)
                    {
                        // adjust a gray pixel
                        CurrentPixel = graySatOp.Apply(CurrentPixel);
                        // adjust pixel alpha
                        if (Amount9 < 0)
                        {
                            CurrentPixel.A = Clamp2Byte((double)CurrentPixel.A + ((double)CurrentPixel.A * ((double)Amount9 / 100.0)));
                        }
                        else if (Amount9 > 0)
                        {
                            CurrentPixel.A = Clamp2Byte((double)CurrentPixel.A + (((255 - (double)CurrentPixel.A) * (double)Amount9 / 100.0)));
                        }
                    }
                }
            }

            *dstPtr = CurrentPixel;
            srcPtr++;
            dstPtr++;
        }
    }
}

 

Download the Visual Studio project here: HueSatPlusSrc.zip

 

Enjoy B):beer:

  • Upvote 5

Share this post


Link to post
Share on other sites

I have updated this plugin to implement a new feature.

Now, when you select the "Preview original image" check box, the other sliders are disabled.

This is a visual reminder that you are not changing the image in any way.

Share this post


Link to post
Share on other sites

I like this plugin very much, and use it quite often, but I wish it had "From Value/To Value" (or "From Lightness/To Lightness") controls.

Share this post


Link to post
Share on other sites

I like this plugin very much, and use it quite often, but I wish it had "From Value/To Value" (or "From Lightness/To Lightness") controls.

Thanks!

The UI is getting pretty long as it is. But, something like that shouldn't be too hard to add. This plugin is actually on my list for a rewrite. So, after I finish my current project, I'll give it a go.

BTW, have you checked out the evanolds plugin I linked to in my original post? It may have the controls you're searching for. (It's been so long since I played with it, I can't remember.)

Share this post


Link to post
Share on other sites

Thanks BoltBait. I haven't tried evanolds's Hue/Saturation plugin, but maybe I'll look at it. For the most part, Hue/Saturation+ does everything I need it to do, even without the Lightness range. There have been occasions, though, when Lightness controls would have been useful.

Share this post


Link to post
Share on other sites

Would it be possible for this plugin to use paint.net's primary and secondary colors? This plugin re-colors things very nicely, but often I wish it could re-color with the choice of using my primary or secondary color.

Share this post


Link to post
Share on other sites

Cc4FuzzyHuggles, in IndirectUI there's no way to set controls to specific values, except to the default values, so I doubt Hue/Saturation+ could support multiple color choices while still using the range-slider interface. A similar control that uses a specified color and tolerances (like the HSV Eraser) could do it. That would probably be a useful plugin, but it wouldn't have the often-convenient ability to directly select the ranges. (I hope that's relatively clear.)

Share this post


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.

Sign in to follow this