Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
convert HEX to RGB
function(
a // take a "#xxxxxx" hex string,
){
a = +( // turn it into a number by taking the
"0x" + // hexadecimal prefix and the
a.slice(1) // numerical portion,
.replace( // and
a.length > 4 // if the #xxxxxx form is used
&& /./g, // replace each character
'$&$&' // with itself twice.
)
);
return [ // return an array
a >> 16, // with red,
a >> 8 & 255, // blue,
a & 255 // and green components.
]
}
function(a){a='0x'+a.slice(1).replace(a.length>4&&/./g,'$&$&');return[a>>16,a>>8&255,a&255]}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 Jed Schmidt <http://jed.is>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "hex2rgb",
"description": "Converts a hex string to RGB.",
"keywords": [
"hex",
"color",
"rgb"
]
}
@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 20, 2011

I came up with this, which is slightly shorter (73 bytes) than your original version of 79 bytes:

function(h){h=parseInt('0x'+h.slice(1));return[h>>16&255,h>>8&255,h&255]}

Of course, meanwhile you reduced your version to 64 bytes and now I feel stupid. Note that my version assumes you pass in a string starting with #, while yours works fine with both strings and numbers. Well done!

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 20, 2011

your parseInt gave me the idea to try something shorter than replace, saving 1 byte.

which do you like better, the current one, or

function(a){a="0x"+a.substr(1);return[+a>>16,+a>>8&255,+a&255]}

?

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 20, 2011

Personally, I like the current one best.

Pro tip: use .slice(1) instead of .substr(1) to save one more byte :) (Bonus: it’s standard, unlike substr.)

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 20, 2011

wow, great tip. too bad String doesn't have splice.

@mgh

This comment has been minimized.

Copy link

@mgh mgh commented May 23, 2011

Nice! How would you make this support strings of length 4 like "#FFF"?

Here's one that's kind of ugly and long, but it works:

function(a,b){b=a.split(""),a=+("0x"+(a.slice(5)?a.slice(1):[b[1],b[1],b[2],b[2],b[3],b[3]].join("")));return[a>>16,a>>8&255,a&255]}
@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 23, 2011

maybe add something like this after the slice?

.replace(/^(.)(.)(.)$/,"$1$1$2$2$3$3")

but first i'd try to see if it could be solved using... MATH!

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 23, 2011

@mathiasbynens, do you think we should add this?

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

@jed Would be cool to support shorter hex notation, as it could end up saving bytes in the long run. Using @jed’s replace solution, calling hex2rgb 13 or more times with a 4-char color would be 1 byte shorter than using the original code with 7-char colors.

x=function(a){a=+("0x"+a.slice(1));return[a>>16,a>>8&255,a&255]};x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');x('#aabbcc');
y=function(a){a=+("0x"+a.slice(1).replace(/^(.)(.)(.)$/,"$1$1$2$2$3$3"));return[a>>16,a>>8&255,a&255]};y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');y('#abc');

That said, would be cool if it was possible using math :)

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 24, 2011

cool, changed. i have doubts that a shorter math solution is possible, but would love to be proved wrong by someone with more chops than i.

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

Different approach inspired by Asen Bozhilov, slightly larger though (105 bytes instead of 100):

function(a){a=a.slice(1);a.length<6&&(a=a.replace(/./g,'$&$&'));a=+('0x'+a);return[a>>16,a>>8&255,a&255]}

This can be golfed down to 99 bytes by checking if a[4] is truthy or not instead of checking the length:

function(a){a=a.slice(1);a[4]||(a=a.replace(/./g,'$&$&'));a=+('0x'+a);return[a>>16,a>>8&255,a&255]}
@pvdz

This comment has been minimized.

Copy link

@pvdz pvdz commented May 24, 2011

If you're assuming the arg is a proper hex with hash prefix, why not just this?
x=function(h){return['0x'+h[1]+h[2]|0,'0x'+h[3]+h[4]|0,'0x'+h[5]+h[6]|0]}

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

@kuvos Nice! Unfortunately it seems to return incorrect results for "#abc": [171,0,0] instead of [170,187,204]. Typo?

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 24, 2011

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

Here’s @kuvos’ solution, with added support for shorthand hex values:

function(h){h[4]||(h=h.replace(/./g,'$&$&').slice(1));return['0x'+h[1]+h[2]|0,'0x'+h[3]+h[4]|0,'0x'+h[5]+h[6]|0]}

113 bytes, so comment #32248 still wins for now.

@pvdz

This comment has been minimized.

Copy link

@pvdz pvdz commented May 24, 2011

ah, yes mine was meant to replace the original :p

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

Another variation of @kuvos’ solution (100 bytes):

function(h,b){b=h[4];return['0x'+h[1]+h[b?2:1]|0,'0x'+h[b?3:2]+h[b?4:2]|0,'0x'+h[b?5:3]+h[b?6:3]|0]}

Caching '0x' doesn’t save any bytes:

function(h,b,x){x='0x';b=h[4];return[x+h[1]+h[b?2:1]|0,x+h[b?3:2]+h[b?4:2]|0,x+h[b?5:3]+h[b?6:3]|0]}

Comment #32248 still wins for now.

@pvdz

This comment has been minimized.

Copy link

@pvdz pvdz commented May 24, 2011

oh right, 'undefined' will be cut off anyways. nice. and yeah, caching '0x' or whatever doesnt matter

@devongovett

This comment has been minimized.

Copy link

@devongovett devongovett commented May 24, 2011

Here's a CoffeeScript version... I win (82 bytes)!

(a)->a=+("0x"+a[1..].replace(/^(.)(.)(.)$/,"$1$1$2$2$3$3"));[a>>16,a>>8&255,a&255]

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 24, 2011

88 bytes:

function(a){a='0x'+a.slice(1).replace(a[4]||/./g,'$&$&')|0;return[a>>16,a>>8&255,a&255]}

by the way, the @qfox trick of exploiting the low precedence of | is genius.

@devongovett

This comment has been minimized.

Copy link

@devongovett devongovett commented May 24, 2011

@jed Chrome and Safari throw parse errors for that last one...

@devongovett

This comment has been minimized.

Copy link

@devongovett devongovett commented May 24, 2011

Nevermind.

@pvdz

This comment has been minimized.

Copy link

@pvdz pvdz commented May 24, 2011

<-- @kuvos ;)

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 24, 2011

<-- @JedSchmidt ;)

@pvdz

This comment has been minimized.

Copy link

@pvdz pvdz commented May 24, 2011

<-- #knews ;) guess i need to thank twitter for screwing up my nickname some day.

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

@jed Wouldn’t that 88-byte version break on #abcdef strings? It would still duplicate a char, no?

94 bytes:

function(a){a='0x'+a.slice(1).replace(a[4]||/./g,a[4]||'$&$&')|0;return[a>>16,a>>8&255,a&255]}
@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 24, 2011

i don't think so... if it's more than 3 digits, the regexp pattern magically turns to undefined, which doesn't match.

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

@jed

.replace(a[4]||/./g,a[4]||'$&$&')

If a[4] is undefined it means it’s a shorthand, and in that case the || kicks in and the regex replace takes place.

If a[4] is truthy it means it’s not a shorthand. The || will be ignored, and the replace would be similar to:

.replace(a[4],'$&$&')

In other words, the character at a[4] would be repeated. No?

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented May 24, 2011

here's what i had before, one more byte but safer:

a[4]?a:/./g

is that okay?

a wont match at this point because it still has the #

@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

I’m confused as to how that would work… Wouldn’t that use the entire string a if a[4] is truthy (not a shorthand) and repeat it?

Oh, just saw your edit:

a wont match at this point because it still has the #.

Doh! Thanks for clarifying :)

@bga

This comment has been minimized.

Copy link

@bga bga commented May 24, 2011

// another path
function(h,b,c){b=.5*!!h[4];c=1;return['0x'+h[c+=b]+h[c+=b]|0,'0x'+h[c+=b]+h[c+=b]|0,'0x'+h[c+=b]+h[c+=b]|0]}

// kuvos's path
function(h,b){b=h[4];return['0x'+h[1]+h[b?2:1]|0,'0x'+h[b?3:2]+h[b?4:2]|0,'0x'+h[b?5:3]+h[b?6:3]|0]}
function(h,b){b=!!h[4];return['0x'+h[1]+h[b+1]|0,'0x'+h[b+2]+h[2*b+2]|0,'0x'+h[2*b+3]+h[3*b+3]|0]}
function(h,b){b=!!h[4];return['0x'+h[1]+h[b+1]|0,'0x'+h[b+2]+h[2*b+2]|0,'0x'+h[2*b+3]+h[3*b+3]|0]}
function(h,b){b=!!h[4]+1;return['0x'+h[1]+h[b]|0,'0x'+h[b+1]+h[2*b]|0,'0x'+h[2*b+1]+h[3*b]|0]}

// Asen's path
function(h){h='0x'+(h[4]?h:h.replace(/./g,'$&$&')).slice(1+!h[4])-0;return[h>>16,h>>8&255,h&255]}
function(h){h=h.slice(1);h[4]||(h=h.replace(/./g,'$&$&'));h='0x'+h-0;return[h>>16,h>>8&255,h&255]}
function(h,b){h='0x'+((b=h[4])?h:h.replace(/./g,'$&$&')).slice(1+!b)-0;return[h>>16,h>>8&255,h&255]}
// + jed's trick
function(h){h='0x'+h.replace(!h[4]&&/./g,'$&$&').slice(1+!h[4])-0;return[h>>16,h>>8&255,h&255]}

//var _fn = 
_log(_fn('#abc'))
_log(_fn('#123456'))
@mathiasbynens

This comment has been minimized.

Copy link

@mathiasbynens mathiasbynens commented May 24, 2011

@bga Great stuff!

!foo && bar can be written as foo || bar, so you could rewrite that last one as follows to save a byte (95→94 bytes):

function(h){h='0x'+h.replace(h[4]||/./g,'$&$&').slice(1+!h[4])-0;return[h>>16,h>>8&255,h&255]}

Edit: Actually, no — that would break it, of course, since it’s used for .replace() so it needs to be false. Ignore me! :)

@bga

This comment has been minimized.

Copy link

@bga bga commented May 24, 2011

@mathiasbynens no.

'#bbaacc'.replace('a', '$&$&')
@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Jul 13, 2011

I've tested the code in IE6, 8, and it returns a wrong result as a string doesn't act like an array in those IE versions. I think a[4] should be replaced by a.length>4

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Jul 13, 2011

fixed. thanks again, @tsaniel!

@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Oct 9, 2011

I find it we can save another byte.

function(a){a='0x'+a.slice(1).replace(a.length>4&&/./g,'$&$&');return[a>>16,a>>8&255,a&255]}
@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 9, 2011

relentless golfing, @tsaniel!

@atk

This comment has been minimized.

Copy link

@atk atk commented Oct 10, 2011

Wait, >4? Doesn't it need to be the other way round, <4?

@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Oct 10, 2011

@atk: Thanks for your carefulness! i just did it anyhow.

@phoetry

This comment has been minimized.

Copy link

@phoetry phoetry commented Dec 9, 2011

Both wrong with >4 and <4
Shound be a.length<5&&/./g

@slidenerd

This comment has been minimized.

Copy link

@slidenerd slidenerd commented Mar 13, 2017

function hexToRgb(hex) {
var number = parseInt(hex, 16);
console.log(number)
var r = (number >> 16) & 255;
var g = (number >> 8) & 255;
var b = number & 255;
console.log(r,g,b)
return {red: r, green: g, blue: b};
}
let rgb = hexToRgb(0xFFFFFF)
Gives 119 114 21 , any ideas why

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment