52

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

71

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

Sign up to request clarification or add additional context in comments.

4 Comments

nice... just need to add a period into the regex to account for rgba float values: rgb.replace(/[^\d,.]/g, '').split(',')
@bob's comment is on point, returns Array [ "255", "255", "255", "0.5" ] for an RGBA array
for HSL might as well add % too: /[^\d,.%]/g
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
25

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 Comments

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"].
True, however if you use only the first three values in the array you will always get the R, G, B values
Use /[\d\.]+/g handle floats.
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. :)

Comments

4

How about using a color library like the xolor library:

xolor("rgb(200,100,40)").r // returns the red part

2 Comments

...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.
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 🙄
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 Comments

this doesn't work for decimal based alpha values
@KFE Use /[\d\.]+/g handle floats
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 Comment

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.
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])

Comments

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]).');
    }
}

Comments

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;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.