Jump to content
How to Install Plugins ×

Duotone Gradient Mapping [v2 2023-04-22]


pascal

Recommended Posts

[April 22th 2023] Version 2 available!

 

Back with my second plugin. This time I made a plugin that can be used to easily and quickly create a gradient mapping effect using 2 colors. I know pyrochild already made a gradient mapping tool, but this is just a simplified version using only 2 colors for dark and light tones. I added some options for post processing as well, like contrast and blending mode.

 

sample.jpg.31e3c2dc513b4a594604f52b2ca51ee8.jpg

 

Download

Location: Effects > Color > Duotone Gradient Map

duotonegradientmap.zip

 

Code

Spoiler
#region UICode
ColorWheelControl DARK = ColorBgra.FromBgr(0, 0, 0); // Dark
ColorWheelControl LIGHT = ColorBgra.FromBgr(255, 255, 255); // Light
IntSliderControl CONTRAST = 0; // [-100,100] Contrast
ListBoxControl<BlendMode> BLEND = 0; // Blending mode|Normal
IntSliderControl MIX = 100; // [0,100] Mix
#endregion
enum BlendMode
{
    Normal, Multiply, Screen, Darken, Lighten, Overlay, Additive
}

Func<byte, byte, byte> blender = null;

void PreRender(Surface dst, Surface src)
{
    blender = BLEND switch
        {
            BlendMode.Multiply => BlendMult,
            BlendMode.Screen => BlendScreen,
            BlendMode.Darken => BlendDarken,
            BlendMode.Lighten => BlendLighten,
            BlendMode.Overlay => BlendOverlay,
            BlendMode.Additive => BlendAdd,
            _ => BlendNormal
        };
}

void Render(Surface dst, Surface src, Rectangle rect)
{
    double mix = MIX / 100.0;
    double contrast = CONTRAST / 10.0;
    
    ColorBgra c;
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
            c = src[x,y];
            double value = Contrast((c.R + c.G + c.B) / 765.0, contrast);
            ColorBgra n = Mix(DARK, LIGHT, value);
            n = ApplyBlend(c, n, blender);
            n = Mix(c, n, mix);
            n.A = c.A;
            dst[x,y] = n;
        }
    }
}

double Contrast(double x, double p)
{
    if (p == 0)
    {
        return x;
    }
    if (p > 0)
    {
        return x < 0.5
            ? 0.5 * Math.Pow(2.0 * x, p + 1.0)
            : 1.0 - 0.5 * Math.Pow(2.0 - 2.0 * x, p + 1.0);
    }
    else {
        return x < 0.5
            ? 0.5 - 0.5 * Math.Pow(1.0 - 2.0 * x, 1.0 - p)
            : 0.5 + 0.5 * Math.Pow(2.0 * x - 1.0, 1.0 - p);
    }
}

ColorBgra Mix(ColorBgra a, ColorBgra b, double value)
{
    return ColorBgra.FromBgr(
        Mix(a.B, b.B, value),
        Mix(a.G, b.G, value),
        Mix(a.R, b.R, value)
    );
}

byte Mix(byte a, byte b, double value)
{
    double output = (1.0 - value) * a + value * b;
    return (byte) Math.Clamp(output, 0.0, 255.0);
}

ColorBgra ApplyBlend(ColorBgra a, ColorBgra b, Func<byte, byte, byte> f)
{
    return ColorBgra.FromBgr(
        f(a.B, b.B), 
        f(a.G, b.G),
        f(a.R, b.R)
    );
}

byte BlendNormal(byte a, byte b)
{
    return b;
}

byte BlendDarken(byte a, byte b)
{
    return Math.Min(a, b);
}

byte BlendLighten(byte a, byte b)
{
    return Math.Max(a, b);
}

byte BlendMult(byte a, byte b)
{
    return (byte) Math.Clamp(a * b * 0.0039215686, 0.0, 255.0);
}

byte BlendScreen(byte a, byte b)
{
    return (byte) (255 - BlendMult((byte) (255 - a), (byte) (255 - b)));
}

byte BlendOverlay(byte a, byte b)
{
    return (byte) (a < 127
        ? 2 * BlendMult(a, b)
        : 2 * BlendScreen(a, b));
}

byte BlendAdd(byte a, byte b)
{
    return (byte) Math.Clamp(a + b, 0, 255);
}

 

Edited by pascal
effect location
  • Like 2
  • Thanks 1
  • Upvote 1

pdnsignature.jpg.bb235358debfd06bf4d9023c840e8aa2.jpg

Link to comment
Share on other sites

//BLENDING MODES

            //multiply
            if(M == 1){

You could clean up the code using Switch /Case for these tests.

 

      switch (M)
      {
          case 1:
              //Console.WriteLine("Case 1");
              break;
          case 2:
              //Console.WriteLine("Case 2");
              break;
          
          ...
            
          default:
              //Console.WriteLine("Default case");
              break;
      }

 

It's not a big thing - but BoltBait & toe_head2001 have got some awesome coloring effects for sliders baked right into Codelab. They look really cool B)

Link to comment
Share on other sites

1 hour ago, Ego Eram Reputo said:

You could clean up the code using Switch /Case for these tests.

 

Using an enum is even cleaner. :D

#region UICode
ListBoxControl<BlendingMode> blendingMode = 0; // Blending mode|Normal|Multiply|Darken|Lighten|Additive
#endregion

enum BlendingMode
{
    Normal,
    Multiply,
    Darken,
    Lighten,
    Additive
}

void Render(Surface dst, Surface src, Rectangle rect)
{
    switch (blendingMode)
    {
        case BlendingMode.Multiply:
            // code here
            break;

        case BlendingMode.Darken:
            // code here
            break;

        case BlendingMode.Lighten:
            // code here
            break;

        case BlendingMode.Additive:
            // code here
            break;

        case BlendingMode.Normal:
        default:
            // code here
            break;
    }
}

 

  • Like 1
  • Upvote 2

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

  • 4 months later...

@pascal - Nice. Whilst the "suggestions" are constructive, you've built some code that can be used. There's always a critic. Your code is entirely readable. Stick with what you feel comfortable with.

Link to comment
Share on other sites

  • pascal changed the title to Duotone Gradient Mapping [v2 2023-04-22]

Version 2 available

- Changed the layout to make it more clear in which order things are applied.

- Contrast now only applies to the color-mapped layer.

- Added more blending modes.

- Made the mix slider independent of blending modes.

- Improved overall code.

  • Like 1
  • Upvote 2

pdnsignature.jpg.bb235358debfd06bf4d9023c840e8aa2.jpg

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.

×
×
  • Create New...