Created
August 29, 2015 11:23
-
-
Save SEVEZ/3dfa1f7807dab5379fe3 to your computer and use it in GitHub Desktop.
Shift RGB colors along RYB artistic color wheel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Preview online | |
// http://www.deathbysoftware.com/colors/index.html | |
function rgb2ryb ( iRed, iGreen, iBlue ) | |
{ | |
// Remove the white from the color | |
var iWhite = Math.min( iRed, iGreen, iBlue ); | |
iRed -= iWhite; | |
iGreen -= iWhite; | |
iBlue -= iWhite; | |
var iMaxGreen = Math.max( iRed, iGreen, iBlue ); | |
// Get the yellow out of the red+green | |
var iYellow = Math.min( iRed, iGreen ); | |
iRed -= iYellow; | |
iGreen -= iYellow; | |
// If this unfortunate conversion combines blue and green, then cut each in half to | |
// preserve the value's maximum range. | |
if (iBlue > 0 && iGreen > 0) | |
{ | |
iBlue /= 2; | |
iGreen /= 2; | |
} | |
// Redistribute the remaining green. | |
iYellow += iGreen; | |
iBlue += iGreen; | |
// Normalize to values. | |
var iMaxYellow = Math.max( iRed, iYellow, iBlue ); | |
if ( iMaxYellow > 0 ) | |
{ | |
var iN = iMaxGreen / iMaxYellow; | |
iRed *= iN; | |
iYellow *= iN; | |
iBlue *= iN; | |
} | |
// Add the white back in. | |
iRed += iWhite; | |
iYellow += iWhite; | |
iBlue += iWhite; | |
return [ iRed, iYellow, iBlue ]; | |
} | |
function ryb2rgb ( iRed, iYellow, iBlue ) | |
{ | |
// Remove the whiteness from the color. | |
var iWhite = Math.min( iRed, iYellow, iBlue ); | |
iRed -= iWhite; | |
iYellow -= iWhite; | |
iBlue -= iWhite; | |
var iMaxYellow = Math.max( iRed, iYellow, iBlue ); | |
// Get the green out of the yellow and blue | |
var iGreen = Math.min( iYellow, iBlue ); | |
iYellow -= iGreen; | |
iBlue -= iGreen; | |
if ( iBlue > 0 && iGreen > 0 ) | |
{ | |
iBlue *= 2.0; | |
iGreen *= 2.0; | |
} | |
// Redistribute the remaining yellow. | |
iRed += iYellow; | |
iGreen += iYellow; | |
// Normalize to values. | |
var iMaxGreen = Math.max( iRed, iGreen, iBlue ); | |
if ( iMaxGreen > 0 ) | |
{ | |
var iN = iMaxYellow / iMaxGreen; | |
iRed *= iN; | |
iGreen *= iN; | |
iBlue *= iN; | |
} | |
// Add the white back in. | |
iRed += iWhite; | |
iGreen += iWhite; | |
iBlue += iWhite; | |
// Save the RGB | |
return [ iRed, iGreen, iBlue ]; | |
} | |
// RGB2HSV and HSV2RGB are based on Color Match Remix [http://color.twysted.net/] | |
// which is based on or copied from ColorMatch 5K [http://colormatch.dk/] | |
function rgbToHsl( r, g, b ) | |
{ | |
var h, s, l | |
max = max3( r, g, b ) | |
dif = max - min3( r, g, b ) | |
s = ( max == 0.0 ) ? 0 : ( dif / max ) | |
if ( s == 0 ) h = 0 | |
else if ( r == max ) h = 60.0 * ( g - b ) / dif | |
else if ( g == max ) h = 120.0 + 60.0 * ( b - r ) / dif | |
else if ( b == max ) h = 240.0 + 60.0 * ( r - g ) / dif | |
if ( h < 0.0 ) h += 360.0 | |
l = max | |
h /= 360.0 | |
return [ h, s, l ] | |
} | |
function hslToRgb( h, s, l ) | |
{ | |
var r, g, b | |
if ( s == 0 ) return [ l, l, l ] | |
else | |
{ | |
var i, f, p ,q ,t | |
h *= 6 | |
i = Math.floor( h ) | |
f = h - i | |
p = l * ( 1 - s ) | |
q = l * ( 1 - s * f ) | |
t = l * ( 1 - s * ( 1 - f ) ) | |
switch( i ) | |
{ | |
case 0: return [ l, t, p ] | |
case 1: return [ q, l, p ] | |
case 2: return [ p, l, t ] | |
case 3: return [ p, q, l ] | |
case 4: return [ t, p, l ] | |
default: return [ l, p, q ] | |
} | |
} | |
} | |
//min max via Hairgami_Master (see comments) | |
function min3(a,b,c) { return ( a < b ) ? ( ( a < c ) ? a : c ) : ( ( b < c ) ? b : c ) } | |
function max3(a,b,c) { return ( a > b ) ? ( ( a > c ) ? a : c ) : ( ( b > c ) ? b : c ) } | |
//Adding HueShift via Jacob (see comments) | |
function HueShift( h, s ) { h += s; while ( h >= 360.0 ) h -= 360.0; while ( h < 0.0 ) h += 360.0; return h; } | |
function ryb2rgb2 ( R, Y, B ) | |
{ | |
R = R * R * ( 3 - 2 * R ) | |
Y = Y * Y * ( 3 - 2 * Y ) | |
B = B * B * ( 3 - 2 * B ) | |
return [1.0 + B * ( R * (0.337 + Y * -0.137) + (-0.837 + Y * -0.163) ), | |
1.0 + B * ( -0.627 + Y * 0.287) + R * (-1.0 + Y * (0.5 + B * -0.693) - B * (-0.627) ), | |
1.0 + B * (-0.4 + Y * 0.6) - Y + R * ( -1.0 + B * (0.9 + Y * -1.1) + Y )] | |
} | |
/* | |
function rotate_ryb( h, angle ) | |
{ | |
// Returns a color rotated on the artistic RYB color wheel. | |
// An artistic color wheel has slightly different opposites | |
// (e.g. purple-yellow instead of purple-lime). | |
// It is mathematically incorrect but generally assumed | |
// to provide better complementary colors. | |
// http://en.wikipedia.org/wiki/RYB_color_model | |
h *= 360 | |
angle %= 360 | |
// log += h + "\n" | |
// log += angle + "\n" | |
// Approximation of Itten's RYB color wheel. | |
// In HSB, colors hues range from 0-360. | |
// However, on the artistic color wheel these are not evenly distributed. | |
// The second tuple value contains the actual distribution. | |
wheel = | |
[ | |
[ 0, 0], | |
[ 15, 8], | |
[ 30, 17], | |
[ 45, 26], | |
[ 60, 34], | |
[ 75, 41], | |
[ 90, 48], | |
[105, 54], | |
[120, 60], | |
[135, 81], | |
[150, 103], | |
[165, 123], | |
[180, 138], | |
[195, 155], | |
[210, 171], | |
[225, 187], | |
[240, 204], | |
[255, 219], | |
[270, 234], | |
[285, 251], | |
[300, 267], | |
[315, 282], | |
[330, 298], | |
[345, 329], | |
[360, 0 ] | |
] | |
// Given a hue, find out under what angle it is | |
// located on the artistic color wheel. | |
var a, x0, x1, y0, y1 | |
for ( var i = 0; i < wheel.length - 1; i++ ) | |
{ | |
x0 = wheel[i][0] | |
y0 = wheel[i][1] | |
x1 = wheel[i+1][0] | |
y1 = wheel[i+1][1] | |
//WScript.Echo( y0 + " <= " + h + " <= " + y1 + "?\n" ) | |
if ( y1 < y0 ) y1 += 360 | |
if ( ( y0 <= h ) && ( h <= y1 ) ) | |
{ | |
a = 1.0 * x0 + ( x1 - x0 ) * ( h - y0 ) / ( y1 - y0 ) // lerp | |
break | |
} | |
} | |
a = ( a + angle ) % 360 | |
// For the given angle, find out what hue is | |
// located there on the artistic color wheel. | |
for ( var i = 0; i < wheel.length-1; i++ ) | |
{ | |
x0 = wheel[i][0] | |
y0 = wheel[i][1] | |
x1 = wheel[i+1][0] | |
y1 = wheel[i+1][1] | |
if ( y1 < y0 ) y1 += 360 | |
if ( ( x0 <= a ) && ( a <= x1 ) ) | |
{ | |
h = 1.0 * y0 + ( y1 - y0 ) * ( a - x0 ) / ( x1 - x0 ) // lerp | |
break | |
} | |
} | |
h %= 360 | |
return h/360 | |
} | |
*/ | |
//----------------------- TESTING | |
var c = [ 0, 0, 1 ] | |
c = rgb2ryb( c[0], c[1], c[2] ) | |
c = rgbToHsl( c[0], c[1], c[2] ) | |
c[0] = HueShift( Math.round( c[0] * 360 ), 0 ) / 360.0 | |
c = hslToRgb( c[0], c[1], c[2] ) | |
c = ryb2rgb2( c[0], c[1], c[2] ) | |
WScript.Echo( "complementary = " + [ Math.round( c[0] * 255 ), Math.round( c[1] * 255 ), Math.round( c[2] * 255 ) ] ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for this :)