10

JS HEX十六进制与RGB, HSL颜色的相互转换

 3 years ago
source link: https://www.zhangxinxu.com/wordpress/2010/03/javascript-hex-rgb-hsl-color-convert/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

by zhangxinxu from https://www.zhangxinxu.com
本文地址:https://www.zhangxinxu.com/wordpress/?p=646

一、关于颜色的表示

颜色的表示方式不知一种,从photoshop的取色面板就可以看出,如下:

颜色的表示方式 张鑫旭-鑫空间-鑫生活

上图共显示了5种颜色的表示方法:HSB,lab,RGB,CMYK与十六进制表示法

在CSS中,我们也经常与颜色打交道,其中有color(文字颜色),还有一个就是background-color背景颜色,还有就是border-color。一般,我们习惯用十六进制表示颜色,//zxx:AS中也是如此,不过是以”0x”打头,而不是”#”,例如黑色表示为:#000000;在CSS 2.1中,还支持RGB的颜色表示法,IE,Firefox等浏览器均支持,例如黑色可以表示为RGB(0, 0, 0);

在CSS3中,增加了 HSL colors HSLA colors RGBA colors表示方法,不过这些这里不讨论。

更多颜色的知识可以点击这里:维基百科-颜色

二、颜色表示方式转换的必要性

这确实是个疑问,虽说在CSS中有两种颜色表示方法,那么为什么还有进行颜色表示方式的转换呢,不都是一样的表示颜色吗?
确实,大多数情况下,转换时没有必要的,但是web页面千变万化,遇到的情况千奇百怪,是有需要转换的情况。

举个我遇到的例子吧,我去年9月份,学习Ajax的时候,做过一个Ajax+PHP多人在线聊天室聊天室(访问该页面点击这里),其中里面有个很重要的工具就是取色面板,用以改变显示的文字颜色的。见下图:

聊天室取色面板 张鑫旭-鑫空间-鑫生活

里面对颜色字符做了些处理,就是以十六进制的形式显示。做处理归根结底的原因就是浏览器的差异,差异如下:
在Firefox浏览器下(chrome同样),即使你使用了十六进制形式表示了颜色值,但是在HTML页面中,其却是以RGB形式表示的,这与IE浏览器是不一致的。也就是说,如果不做字符显示的处理的话,那么Firefox浏览器下,上面的聊天颜色面板获得的值就是类似于RGB(255,0,0)这种形式的,而不是”#FF0000″,我们可以做个简单的测试,看如下的代码。

<button style="color:#ff3300;" onclick="javascript:alert(this.style.color);">点击我</button>

结果Firefox下的显示是,如下图:

Firefox浏览器下的颜色显示 张鑫旭-鑫空间-鑫生活

而IE浏览器下则是:
IE浏览器下颜色的表示 张鑫旭-鑫空间-鑫生活

您可以自己点击下面的按钮测试一下:

可见,这种颜色表示的差异性,使得有时候,颜色转换成为的必须。

三、JavaScript颜色转换的核心

JavaScript颜色转换的核心就是进制间的转换。RGB格式其实就是十进制表示法,所以,十六进制颜色与RGB颜色的转换就是十六进制与十进制之间的转换。

十六进制转换为十进制相对容易些,核心代码如下示例:parseInt("0xFF"),其结果就是255,”0x”就表明当前是16进制,由于parseInt后面无参数,默认就是转换为10进制了。

十进制转换为16进制,核心代码如下:var num=255; num.toString(16);,其结果是FF。”16″表示数值转换为16进制字符串。

四、JavaScript颜色表示方式的转换的实现

转换代码如下,首先是RGB颜色转换为十六进制表示:

String.prototype.colorHex = function(){
    var that = this;
    //十六进制颜色值的正则表达式
    var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
    // 如果是rgb颜色表示
    if (/^(rgb|RGB)/.test(that)) {
        var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
        var strHex = "#";
        for (var i=0; i<aColor.length; i++) {
            var hex = Number(aColor[i]).toString(16);
            if (hex.length < 2) {
                hex = '0' + hex;    
            }
            strHex += hex;
        }
        if (strHex.length !== 7) {
            strHex = that;    
        }
        return strHex;
    } else if (reg.test(that)) {
        var aNum = that.replace(/#/,"").split("");
        if (aNum.length === 6) {
            return that;    
        } else if(aNum.length === 3) {
            var numHex = "#";
            for (var i=0; i<aNum.length; i+=1) {
                numHex += (aNum[i] + aNum[i]);
            }
            return numHex;
        }
    }
    return that;
};

然后是十六进制颜色转为RGB格式:

String.prototype.colorRgb = function(){
    var sColor = this.toLowerCase();
    //十六进制颜色值的正则表达式
    var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
    // 如果是16进制颜色
    if (sColor && reg.test(sColor)) {
        if (sColor.length === 4) {
            var sColorNew = "#";
            for (var i=1; i<4; i+=1) {
                sColorNew += sColor.slice(i, i+1).concat(sColor.slice(i, i+1));    
            }
            sColor = sColorNew;
        }
        //处理六位的颜色值
        var sColorChange = [];
        for (var i=1; i<7; i+=2) {
            sColorChange.push(parseInt("0x"+sColor.slice(i, i+2)));    
        }
        return "RGB(" + sColorChange.join(",") + ")";
    }
    return sColor;
};

上面颜色转换方法使用示意:

var sRgb = "RGB(23, 245, 56)" , sHex = "#34538b";
var sHexColor = sRgb.colorHex();
var sRgbColor = sHex.colorRgb();

其中colorHex()表示转换为十六进制方法,colorRgb()表示转为RGB颜色值的方法。

您可以狠狠地点击这里:测试demo页面

您也可以直接在下面进行测试:

十六进制颜色值:

GRB颜色值:

说明:此JavaScript实现的一个小小原则是“以统一的形式显示”,所以十六进制缩写的颜色值(如:#333)会以#333333显示。如果转为的字符格式不匹配或是值溢出返回,则会原值返回。例如:RGB(0,0,256)会返回RGB(0,0,256),#3456会返回#3456,#egd会返回#egd。

新增于2015-05-20
这里再附上HSL转RGB以及RGB转HSL的代码,出处见这里

HSL转RGB

/**
 * HSL颜色值转换为RGB. 
 * 换算公式改编自 http://en.wikipedia.org/wiki/HSL_color_space.
 * h, s, 和 l 设定在 [0, 1] 之间
 * 返回的 r, g, 和 b 在 [0, 255]之间
 *
 * @param   Number  h       色相
 * @param   Number  s       饱和度
 * @param   Number  l       亮度
 * @return  Array           RGB色值数值
 */
function hslToRgb(h, s, l) {
    var r, g, b;

    if(s == 0) {
        r = g = b = l; // achromatic
    } else {
        var hue2rgb = function hue2rgb(p, q, t) {
            if(t < 0) t += 1;
            if(t > 1) t -= 1;
            if(t < 1/6) return p + (q - p) * 6 * t;
            if(t < 1/2) return q;
            if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
            return p;
        }

        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;
        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);
    }

    return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}

RGB转HSL

/**
 * RGB 颜色值转换为 HSL.
 * 转换公式参考自 http://en.wikipedia.org/wiki/HSL_color_space.
 * r, g, 和 b 需要在 [0, 255] 范围内
 * 返回的 h, s, 和 l 在 [0, 1] 之间
 *
 * @param   Number  r       红色色值
 * @param   Number  g       绿色色值
 * @param   Number  b       蓝色色值
 * @return  Array           HSL各值数组
 */
function rgbToHsl(r, g, b) {
    r /= 255, g /= 255, b /= 255;
    var max = Math.max(r, g, b), min = Math.min(r, g, b);
    var h, s, l = (max + min) / 2;

    if (max == min){ 
        h = s = 0; // achromatic
    } else {
        var d = max - min;
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
        switch(max) {
            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
            case g: h = (b - r) / d + 2; break;
            case b: h = (r - g) / d + 4; break;
        }
        h /= 6;
    }

    return [h, s, l];
}

这里转换的HSL并不能直接当作CSS颜色值处理,因为范围不一样。

H指Hue(色调)。 0(或360)表示红色,120表示绿色,240表示蓝色,当然可取其他数值来确定其它颜色;
S指Saturation(饱和度)。 取值为0%到100%之间的值;
L指Lightness(亮度)。 取值为0%到100%之间的值;

自己需要再转换下。

关于HSL,可以参见这里:css3-hsl-colors

补充于2018-11-23
增加个RGB转HSB/HSV的方法:

function rgbToHsv(r, g, b) {
    r = r / 255;
    g = g / 255;
    b = b / 255;
    var h, s, v;
    var min = Math.min(r, g, b);
    var max = v = Math.max(r, g, b);
    var l = (min + max) / 2;
    var difference = max - min;

    if (max == min) {
        h = 0;
    } else {
        switch (max) {
        case r:
            h = (g - b) / difference + (g < b ? 6 : 0);
            break;
        case g:
            h = 2.0 + (b - r) / difference;
            break;
        case b:
            h = 4.0 + (r - g) / difference;
            break;
        }
        h = Math.round(h * 60);
    }
    if (max == 0) {
        s = 0;
    } else {
        s = 1 - min / max;
    }
    s = Math.round(s * 100);
    v = Math.round(v * 100);
    return [h, s, v];
}

补充于2020-06-29
今天发现需要用到HSV/HSB转RGB色值的场景,补上一段代码:

// 参数arr的3个值分别对应[h, s, v]
function hsvToRgb(arr) {
    var h = arr[0], s = arr[1], v = arr[2];
    s = s / 100;
    v = v / 100;
    var r = 0, g = 0, b = 0;
    var i = parseInt((h / 60) % 6);
    var f = h / 60 - i;
    var p = v * (1 - s);
    var q = v * (1 - f * s);
    var t = v * (1 - (1 - f) * s);
    switch (i) {
        case 0:
            r = v; g = t; b = p;
            break;
        case 1:
            r = q; g = v; b = p;
            break;
        case 2:
            r = p; g = v; b = t;
            break;
        case 3:
            r = p; g = q; b = v;
            break;
        case 4:
            r = t; g = p; b = v;
            break;
        case 5:
            r = v; g = p; b = q;
            break;
        default:
            break;
    }
    r = parseInt(r * 255.0)
    g = parseInt(g * 255.0)
    b = parseInt(b * 255.0)
    return [r, g, b];
}

补充于2017年9月19日
再补充个任意色值(甚至是CSS颜色关键字)转换为RGB颜色的方法,此方法IE9+浏览器支持,基于DOM特性实现。

var colorToRgb = function (color) {
    var div = document.createElement('div');
    div.style.backgroundColor = color;
    document.body.appendChild(div);
    var c = window.getComputedStyle(div).backgroundColor;    
    document.body.removeChild(div);
    return c;
};

需要保证color是不带透明度的,否则最后得到的回事RGBA颜色,而不是RGB颜色。

我js资历尚浅,所以代码可能会遇到以下些不足:
1、可能漏了些特殊情况;
2、在效率方面还可以进一步改进;
3、在算法上可以进一步优化;

欢迎指出这些不足。

(本篇完)1f44d.svg 是不是学到了很多?可以分享到微信
1f44a.svg 有话要说?点击这里


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK