51

I'm using Javascript and Canvas to make a painting app and was using strings in this format to designate chosen colors:

"rgb(255,0,0)"

Because the canvas context fillStyle property takes in strings of that format.

However, I now need to obtain individual components from this string and was wondering if there was a way to do it without messy string manipulation. Possibly some built in way to convert that string to a sort of color object and then access its r, g, and b components?

Thanks.

1
  • 1
    Not that I'm aware of, but I'd be fascinated to be proven wrong. Commented Jun 10, 2012 at 17:55

9 Answers 9

68

NOTE - We're all on board with the regex ate my brains and kicked my dog attitude, but the regex version just seems the better method. My opinion. Check it out.

Non-regex method:

var rgb = 'rgb(200, 12, 53)';

rgb = rgb.substring(4, rgb.length-1)
         .replace(/ /g, '')
         .split(',');

console.log(rgb);

http://jsfiddle.net/userdude/Fg9Ba/

Outputs:

["200", "12", "53"]

Or... A really simple regex:

EDIT: Ooops, had an i in the regex for some reason.

var rgb = 'rgb(200, 12, 53)';

rgb = rgb.replace(/[^\d,]/g, '').split(',');

console.log(rgb);

http://jsfiddle.net/userdude/Fg9Ba/2

4
  • 14
    nice... just need to add a period into the regex to account for rgba float values: rgb.replace(/[^\d,.]/g, '').split(',')
    – bob
    Commented Apr 16, 2015 at 3:31
  • 1
    @bob's comment is on point, returns Array [ "255", "255", "255", "0.5" ] for an RGBA array Commented Nov 9, 2016 at 16:11
  • 1
    for HSL might as well add % too: /[^\d,.%]/g
    – bryc
    Commented Jul 24, 2018 at 11:49
  • What if we use a malformed input like rgb(234, 789, 999, -3, 2, 0.765, -6.78)? This has both floats, numbers above 255, negatives and has more than 3 values, and it would be parsed like nothing happened
    – Ath.Bar.
    Commented Feb 8, 2023 at 18:06
24

much simpler way ..

    var rgb = 'rgb(200, 12, 53)'.match(/\d+/g);
    console.log(rgb);  

and here comes the output as

    ["200", "12", "53"]

" simple is always beautiful ! " :)

3
  • 14
    This fails when an alpha channel is present, e.g. rgba(1, 1, 1, 0.6), in which case it returns ["1", "1", "1", "0", "6"]. Commented Nov 9, 2015 at 21:55
  • 1
    True, however if you use only the first three values in the array you will always get the R, G, B values
    – Dror Bar
    Commented Oct 25, 2020 at 9:24
  • 1
    Use /[\d\.]+/g handle floats. Commented Oct 23, 2022 at 1:20
6

My version takes a HEX, RGB or RGBa string as an argument, uses no regEx, and returns an object with red, green, and blue (and alpha for RGBa) number-values.

var RGBvalues = (function() {

    var _hex2dec = function(v) {
        return parseInt(v, 16)
    };

    var _splitHEX = function(hex) {
        var c;
        if (hex.length === 4) {
            c = (hex.replace('#','')).split('');
            return {
                r: _hex2dec((c[0] + c[0])),
                g: _hex2dec((c[1] + c[1])),
                b: _hex2dec((c[2] + c[2]))
            };
        } else {
             return {
                r: _hex2dec(hex.slice(1,3)),
                g: _hex2dec(hex.slice(3,5)),
                b: _hex2dec(hex.slice(5))
            };
        }
    };

    var _splitRGB = function(rgb) {
        var c = (rgb.slice(rgb.indexOf('(')+1, rgb.indexOf(')'))).split(',');
        var flag = false, obj;
        c = c.map(function(n,i) {
            return (i !== 3) ? parseInt(n, 10) : flag = true, parseFloat(n);
        });
        obj = {
            r: c[0],
            g: c[1],
            b: c[2]
        };
        if (flag) obj.a = c[3];
        return obj;
    };

    var color = function(col) {
        var slc = col.slice(0,1);
        if (slc === '#') {
            return _splitHEX(col);
        } else if (slc.toLowerCase() === 'r') {
            return _splitRGB(col);
        } else {
            console.log('!Ooops! RGBvalues.color('+col+') : HEX, RGB, or RGBa strings only');
        }
    };

    return {
        color: color
    };
}());

console.debug(RGBvalues.color('rgb(52, 86, 120)'));
  //-> { r: 52, g: 86, b: 120 }
console.debug(RGBvalues.color('#345678'));
  //-> { r: 52, g: 86, b: 120 }
console.debug(RGBvalues.color('rgba(52, 86, 120, 0.67)'));
  //-> { r: 52, g: 86, b: 120, a: 0.67 }
console.debug(RGBvalues.color('#357'));
  //-> { r: 51, g: 85, b: 119 }

Might be useful to someone. :)

4

How about using a color library like the xolor library:

xolor("rgb(200,100,40)").r // returns the red part
2
  • ...using a 29kb library to do a task that can be accomplished with ¹/₆₆₃ʳᵈ of the bloat (a single line of code) is just wrong on so many levels.
    – ashleedawg
    Commented Jun 29, 2020 at 1:45
  • 1
    Its only 13kb uncompressed. 6kb when minified and gzipped. I'm sorry that I'm proposing anyone use modular design instead of rolling their own garbage error prone regex. What was I thinking 🙄
    – B T
    Commented Jun 30, 2020 at 18:22
3

If you are interested in RGB(A) as number values:

const [r,g,b,a] = "rgb(50,205,50)".match(/\d+/g).map(Number);

Note alpha (a) is undefined if there are just 3 numbers in the string!

2
1

Even if you are sure the colors will be in rgb format, and not rgbA, hex, color name, or hsl, you can still have 'rgb(25%,55%,100%)'.

function Rgb(rgb){
    if(!(this instanceof Rgb)) return new Rgb(rgb);
    var c= rgb.match(/\d+(\.\d+)?%?/g);
    if(c){
        c= c.map(function(itm){
            if(itm.indexOf('%')!= -1) itm= parseFloat(itm)*2.55;
            return parseInt(itm);
        });
    }
    this.r= c[0];
    this.g= c[1];
    this.b= c[2];
}

var c= Rgb('rgb(10%,25%,55%)'); alert([c.r, c.g, c.b])

note- If you are using canvas, you have map.

otherwise-

Array.prototype.map=Array.prototype.map || function(fun, scope){
        var T= this, L= T.length, A= Array(L), i= 0;
        if(typeof fun== 'function'){
            while(i<L){
                if(i in T){
                    A[i]= fun.call(scope, T[i], i, T);
                }
                ++i;
            }
            return A;
        }
    }
1
  • It's not legal to have a floating point number in an rgb value, right? I guess if you validated the string, you could test for and reject that and other color formats like rgba. Commented Jun 10, 2012 at 19:04
0

For people using a color picker, this library also allows to convert colors in many formats: https://tovic.github.io/color-picker/

CP.RGB2HEX([255, 255, 255])
0

A (kind of) simple regex solution is implemented in Mozilla Fathom, which can recognize alpha as well:

/**
 * Return the extracted [r, g, b, a] values from a string like "rgba(0, 5, 255, 0.8)",
 * and scale them to 0..1. If no alpha is specified, return undefined for it.
 */
export function rgbaFromString(str) {
    const m = str.match(/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/i);
    if (m) {
        return [m[1] / 255, m[2] / 255, m[3] / 255, m[4] === undefined ? undefined : parseFloat(m[4])];
    } else {
        throw new Error('Color ' + str + ' did not match pattern rgb[a](r, g, b[, a]).');
    }
}
0

Long but working for both RGB string abd RGBA string to number array.

function rgbStringToArray(rgbString){
        let arr=rgbString.replace(/ /g,'').slice(
            rgbString.indexOf("(") + 1,
            rgbString.indexOf(")")
        ).split(",");
        for(let i=0;i<arr.length;i++){
            if(arr.length-1===i && arr.length===4) 
                arr[i]=parseFloat(arr[i]); 
            else 
                arr[i]=parseInt(arr[i]);
        }
        return arr;
    }

Not the answer you're looking for? Browse other questions tagged or ask your own question.