Quantcast
Channel: Rainmeter Forums
Viewing all articles
Browse latest Browse all 1056

Community Tips & Tricks • Automatic Complementary Colors

$
0
0
Automatic Complementary Colors
HSL formulas were researched by Yincognito and I

Today I'd like to share 2 methods to obtain Complementary Colors from any given RGB code with only one measure, no lua required. At the end you'll find an Example Skin.

First things first.

What's a Complementary Color?

A Complementary Color is a color opposite to another color. When combined, cancel each other out to produce a grayscale color. You see complementary colors all the time, take a look at the Rainmeter Logo, it is using Teal and its complementary color, orange. Any brand or product we can think of uses complementary colors, every film you watch is graded using complementary colors (The most famous teal and orange aka "cinematic look"). Even in Nature. You can find complementary colors on different kinds of flowers, or even in the sunset and the ocean. These colors look good together, they are used for various purposes in art, design, and visual communication because they create contrast and enhance each other's intensity when placed side by side. They can make elements stand out, create dynamic compositions, and evoke certain moods or emotions in viewers. So there might be a chance you want to use these colors on your skin, so let's dive into it.

RGB Method

It's important to note that this method is not accurate, it messes with both saturation and luminance (A "true" complementary color preserves both luminance and saturation). Which makes it actually pretty good to create a bright text color against a dark background or vice versa.

ezgif.com-video-to-gif-converter.gif

Doing it is pretty easy, you only need to subtract 255 from each RGB value. Like this:

ComplementaryColor=(255-R),(255-G),(255-B)

You may think it is necessary to separate each RGB value before being able to compute the formula like this:

Code:

;Splits 42,109,154 into R, G and B:[R]Group=AttributesMeasure=StringString=42,109,154RegExpSubstitute=1Substitute="^(\d+),(\d+),(\d+)$":"\1"DynamicVariables=1[G]Group=AttributesMeasure=StringString=42,109,154RegExpSubstitute=1Substitute="^(\d+),(\d+),(\d+)$":"\2"DynamicVariables=1[B]Group=AttributesMeasure=StringString=42,109,154RegExpSubstitute=1Substitute="^(\d+),(\d+),(\d+)$":"\3"DynamicVariables=1
An then subtract 255 from each measure with another 3 measures and then use those results on the options and blah blah blah.

Not really, we can do everything in a single string measure by taking advantage of substitution and then letting the Color options do the math. Like this:

Code:

[ComplementaryColor];This measure generates a complementary color.Measure=StringString=42,109,154RegExpSubstitute=1Substitute="^(\d+),(\d+),(\d+)$":"(255-\1),(255-\2),(255-\3)"DynamicVariables=1
This measure grabs the color "42,109,154" and delivers the string (255-42),(255-109),(255-154). And that's it, now we just use [ComplementaryColor] as a variable on any color option (DynamicVariables=1 required). Fortunately color options can do math. No extra calc measure needed.

HSL Method

This method is the accurate one. It only shifts the hue while letting saturation and luminance intact. It's a little (ok, maybe a lot) more complicated, but it's as easy to use, this method doesn't work for any shade of grey (there's no hue on grey).

ezgif.com-video-to-gif-converter (1).gif
This method requires converting RGB colors to HSL and then back to RGB. Let's do it step by step first to understand the final one-measure implementation.

First we split the RGB values using substitutions:

Code:

[R]Measure=StringString=42,109,154RegExpSubstitute=1Substitute="^(\d+),(\d+),(\d+)$":"\1"DynamicVariables=1[G]Measure=StringString=42,109,154RegExpSubstitute=1Substitute="^(\d+),(\d+),(\d+)$":"\2"DynamicVariables=1[B]Measure=StringString=42,109,154RegExpSubstitute=1Substitute="^(\d+),(\d+),(\d+)$":"\3"DynamicVariables=1
Then we calculate Hue, Saturation and Luminance using the appropriate formulas:

Code:

[H]Measure=CalcFormula=(clamp((round(((Max(Max(([R]/255),([G]/255)),([B]/255))=Min(Min(([R]/255),([G]/255)),([B]/255)))?(0):(((Max(Max(([R]/255),([G]/255)),([B]/255))=([R]/255))?((6+(([G]/255)-([B]/255))/(Max(Max(([R]/255),([G]/255)),([B]/255))-Min(Min(([R]/255),([G]/255)),([B]/255))+0.000001))%6):((Max(Max(([R]/255),([G]/255)),([B]/255))=([G]/255))?((([B]/255)-([R]/255))/(Max(Max(([R]/255),([G]/255)),([B]/255))-Min(Min(([R]/255),([G]/255)),([B]/255))+0.000001)+2):((Max(Max(([R]/255),([G]/255)),([B]/255))=([B]/255))?((([R]/255)-([G]/255))/(Max(Max(([R]/255),([G]/255)),([B]/255))-Min(Min(([R]/255),([G]/255)),([B]/255))+0.000001)+4):(0))))*60)),3)),0,360))DynamicVariables=1[L]Measure=CalcFormula=(clamp((round(((Max(Max(([R]/255),([G]/255)),([B]/255))+Min(Min(([R]/255),([G]/255)),([B]/255)))/2),3)),0,1))DynamicVariables=1[S]Measure=CalcFormula=(clamp((round(((([L]=0)||([L]=1))?(0):((Max(Max(([R]/255),([G]/255)),([B]/255))-[L])/(Min([L],1-[L])+0.000001))),3)),0,1))DynamicVariables=1
(If you want the formulas explained, ask Yincognito, he's better at diving into technicalities than me.)

Now we calculate the Complementary colors using the HSL to RGB formulas, but adding 180 "degrees" to the hue.

Code:

[CR]Measure=CalcFormula=((Clamp(((round(([L]-[S]*Min([L],1-[L])*Max(-1,Min(Min(((0+([H]+180)/30)%12)-3,9-((0+([H]+180)/30)%12)),1))),3))*255),0,255)))DynamicVariables=1[CG]Measure=CalcFormula=(Clamp(((round(([L]-[S]*Min([L],1-[L])*Max(-1,Min(Min(((8+([H]+180)/30)%12)-3,9-((8+([H]+180)/30)%12)),1))),3))*255),0,255))DynamicVariables=1[CB]Measure=CalcFormula=(Clamp(((round(([L]-[S]*Min([L],1-[L])*Max(-1,Min(Min(((4+([H]+180)/30)%12)-3,9-((4+([H]+180)/30)%12)),1))),3))*255),0,255))DynamicVariables=1
And that's it, now you can use [CR],[CG],[CB] on any color option.

As you can see there are a lot of steps we need to take to be able to obtain true complementary colors, fortunately we can just do all that in an single measure using the same trick we used on the RGB method with substitution:

Code:

[ComplementaryColor];This measure generates a complementary color.Measure=StringString=42,109,154RegExpSubstitute=1Substitute="^(\d+),(\d+),(\d+)$":"((Clamp(((round(((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))-(clamp((round(((((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))=0)||((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))=1))?(0):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))/(Min((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)),1-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))+0.000001))),3)),0,1))*Min((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)),1-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))*Max(-1,Min(Min(((0+((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=Min(Min(((\1)/255),((\2)/255)),((\3)/255)))?(0):(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\1)/255))?((6+(((\2)/255)-((\3)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001))%6):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\2)/255))?((((\3)/255)-((\1)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+2):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\3)/255))?((((\1)/255)-((\2)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+4):(0))))*60)),3)),0,360))+180)/30)%12)-3,9-((0+((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=Min(Min(((\1)/255),((\2)/255)),((\3)/255)))?(0):(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\1)/255))?((6+(((\2)/255)-((\3)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001))%6):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\2)/255))?((((\3)/255)-((\1)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+2):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\3)/255))?((((\1)/255)-((\2)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+4):(0))))*60)),3)),0,360))+180)/30)%12)),1))),3))*255),0,255))),(Clamp(((round(((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))-(clamp((round(((((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))=0)||((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))=1))?(0):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))/(Min((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)),1-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))+0.000001))),3)),0,1))*Min((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)),1-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))*Max(-1,Min(Min(((8+((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=Min(Min(((\1)/255),((\2)/255)),((\3)/255)))?(0):(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\1)/255))?((6+(((\2)/255)-((\3)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001))%6):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\2)/255))?((((\3)/255)-((\1)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+2):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\3)/255))?((((\1)/255)-((\2)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+4):(0))))*60)),3)),0,360))+180)/30)%12)-3,9-((8+((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=Min(Min(((\1)/255),((\2)/255)),((\3)/255)))?(0):(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\1)/255))?((6+(((\2)/255)-((\3)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001))%6):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\2)/255))?((((\3)/255)-((\1)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+2):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\3)/255))?((((\1)/255)-((\2)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+4):(0))))*60)),3)),0,360))+180)/30)%12)),1))),3))*255),0,255)),(Clamp(((round(((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))-(clamp((round(((((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))=0)||((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1))=1))?(0):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))/(Min((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)),1-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))+0.000001))),3)),0,1))*Min((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)),1-(clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))+Min(Min(((\1)/255),((\2)/255)),((\3)/255)))/2),3)),0,1)))*Max(-1,Min(Min(((4+((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=Min(Min(((\1)/255),((\2)/255)),((\3)/255)))?(0):(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\1)/255))?((6+(((\2)/255)-((\3)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001))%6):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\2)/255))?((((\3)/255)-((\1)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+2):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\3)/255))?((((\1)/255)-((\2)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+4):(0))))*60)),3)),0,360))+180)/30)%12)-3,9-((4+((clamp((round(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=Min(Min(((\1)/255),((\2)/255)),((\3)/255)))?(0):(((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\1)/255))?((6+(((\2)/255)-((\3)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001))%6):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\2)/255))?((((\3)/255)-((\1)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+2):((Max(Max(((\1)/255),((\2)/255)),((\3)/255))=((\3)/255))?((((\1)/255)-((\2)/255))/(Max(Max(((\1)/255),((\2)/255)),((\3)/255))-Min(Min(((\1)/255),((\2)/255)),((\3)/255))+0.000001)+4):(0))))*60)),3)),0,360))+180)/30)%12)),1))),3))*255),0,255))"DynamicVariables=1
Yep, that's a 7,498 character single liner formula. It grabs the RGB color, splits it, converts it to HSL, adds 180 to the Hue and finally merges it back. Now you can simply use [ComplementaryColor] on any color option and let that meter compute the formula (DynamicVariables=1 required).

That's it, with this 2 methods you can generate complementary colors instantly. Here's an Example skin that also explains both methods. It also includes a fully functional Complementary Color Finder that uses both methods, RGB for the Text color against the background color and HSL for the actual color finder.
Captura de pantalla 2024-03-04 190035.jpg

Statistics: Posted by RicardoTM — Today, 1:02 am



Viewing all articles
Browse latest Browse all 1056

Trending Articles