颜色的世界
原创文章,未经允许,请勿转载
颜色表示方法
自然界的颜色有无数种,我们用数字来表示有限的颜色种类,根据三基色原理,人眼对红、绿、蓝最为敏感,大多数的颜色可以通过红、绿、蓝三色按照不同的比例合成产生,比如:红色+绿色=黄色
、绿色+蓝色=青色
、红色+青色=白色(二次叠加)
用 R、G、B
三个字节表示颜色,可以表示 256*256*256 = 16777216
种颜色,这种颜色我们称之为真彩色
,是目前电脑能表示的最高色彩,也是普遍认为人眼对颜色的最大分辨能力。
我们平常所说的 RGBA
里的 A
(alpha)指的是透明度,透明度不是颜色的一部分,而是用于图层/颜色混合时的叠加度量值
由于早期电脑内存宝贵,一张图片如果使用真彩色存储比较浪费,所以早期电脑程序使用了减配的字节来表示 rgb,比如:
用一个字节表示:RGB332(3+3+2=8 位色):(2^3)(2^3)(2^2)=256(256 Color) 俗称 256 色
用两个字节表示:RGB555(5+5+5=15 位色):(2^5)(2^5)(2^5)=32768(32768/1024=32, 32K Color) 有 1 位未使用
另外一种用两个字节表示:RGB565(5+6+5=16 位色):(2^5)(2^6)(2^5)=65536(65536/1024=32, 64K Color) 由于人眼对绿色最敏感,所有绿色分量占比会多一些
我们常用的RGB
和RGBA
格式属于RGB888
,就是 RGB 各个分量分别占用 8 位,除了 RGB,在印刷工业领域还会使用HSL
表示法,HSL 分别为 hue
(色相)、saturation
(饱和度)、lightness
(亮度)
他们都是可以通过计算公式互相转换的,在内存存储上有区别之外,本质上没有区别
我们来看一个具体的例子,比如下面这个颜色
#5697ff
= rgb(86, 151, 255)
= hsl(217, 100%, 67%)
首先 #5697ff
= rgb(86, 151, 255)
这两种表示方法很容易理解,只是 16 进制和 10 进制的表现形式, 0x56 = 86
。重点看下 HSL,这个三个值不是那么直观的能计算出来
这里有一个js版本的RGB和HSL互转代码
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)];
}
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];
}
色相、饱和度、亮度
那么色相、饱和度、亮度到底代表什么呢?
hue
色相,和人眼直观所见的颜色相关,赤橙黄绿青蓝紫saturation
饱和度,颜色的鲜艳程度,饱和度越小,图像越趋于灰度图像。饱和度越大,图像越鲜艳,给人的感觉是彩色的,而不是黑白灰的图像lightness
亮度,亮度仅与图像的最多颜色成分和最少的颜色成分的总量有关。亮度越小,图像越趋于黑色。亮度越高图像越趋于明亮的白色
用过fireworks
或者photoshop
的同学应该对上面几个概念比较熟悉,因为直接操作 RGB 是比较困难的,比如我们想让图像变亮一些,本质上可以通过改变 RGB 分量来达到目的,但是没那么直观,如果操作 HSL,那么问题就变得简单多了,直接改变 L 分量就可以了。
我们来改一下上面的颜色,把亮度提高 10%,hsl(217, 100%, 67%)
改为 hsl(217, 100%, 77%)
把饱和度设置为 0,则会变为灰度图像,hsl(217, 100%, 67%)
改为 hsl(217, 0%, 67%)
把亮度设置为 0,则会变为黑色图像,hsl(217, 100%, 67%)
改为 hsl(217, 100%, 0%)
色相的值通常在 0 ~ 360 之间,我写了一个 css 渐变来直观感受一下色相从 0 到 360 的分布
饱和度 100% 亮度 50%
饱和度 50% 亮度 50%
饱和度 100% 亮度 90%
颜色的混合
一张半透明的蓝色图片覆盖在一张红色图片上,会呈现什么颜色?早期的计算机程序里面颜色是没有 alpha 透明度的,所以没有漂亮的异形窗口,不是因为做不到,而是颜色混合算法比较费性能,需要按图片分层,然后一个像素一个像素的计算混合后的颜色,实际上颜色混合算法是一个挺大的范畴,各种各样的算法,包括使用汇编指令优化等一些高级玩法
图层普通alpha混合算法如下:
pixel = alpha * image + background * (1 - alpha)
我们实现一个 js 版本的看看
let backdrop = { r: 255, g: 0, b: 0, a: 1 } //红色
let foreground = { r: 0, g: 0, b: 255, a: 0.5 } //半透明蓝色
let result = {
r: Math.round(foreground.r * foreground.a + backdrop.r * (1.0 - foreground.a)),
g: Math.round(foreground.g * foreground.a + backdrop.g * (1.0 - foreground.a)),
b: Math.round(foreground.b * foreground.a + backdrop.b * (1.0 - foreground.a)),
}
console.log(`rgb(${result.r},${result.g},${result.b})`) //output rgb(128,0,128)
得到的结果是 rgb(128,0,128)
,我们用 svg 来演示一下
其他颜色编码格式
另外一种在视频处理领域比较常见的是YUV
格式,摄像头输出、彩色电视信号、相机存储(JPG/JPEG文件格式)都使用YUV格式,Y存储了亮度,而UV存储了调色盘/颜色偏移量数据
YUV的发明是由于彩色电视与黑白电视的过渡时期。黑白视频只有Y(Luma,Luminance)视频,也就是灰阶值。到了彩色电视规格的制定,是以YUV/YIQ的格式来处理彩色电视图像,把UV视作表示彩度的C(Chrominance或Chroma),如果忽略C信号,那么剩下的Y(Luma)信号就跟之前的黑白电视频号相同,这样一来便解决彩色电视机与黑白电视机的兼容问题。YUV最大的优点在于只需占用极少的带宽
网页渲染过程
渲染的过程就是把网页元素栅格化、平面化的过程,把元素按照渲染算法,合并到一张图片上,这张图片称之为帧缓冲(framebuffer),是存在于内存中的一个二维数组,每个数组元素是一个4字节的结构,栅格化可以通过CPU也可以通过GPU,通过GPU渲染就是所谓的硬件加速
一般把一棵dom树混合到一张平面图上,最常见的算法是画家算法
,所谓画家算法就是从后向前绘制,像画油画一样,后面刷的颜色把之前的颜色覆盖,以下面这棵dom树为例,先画body(比如body上有设置背景色)再画 header,然后是content,sesion1、secrion2,然后是footer
body
├── header
├── content
│ ├── section1
│ └── section2
└── footer
使用z-index可以改变渲染顺序,这样就改变了显示的前后层次
栅格化之后,这个缓冲区会再次作为子组件与浏览器标签页、浏览器、操作系统等通过各层API传递,最终显示到显示器上
相关链接
https://www.w3.org/TR/compositing-1/#compositemode
来源:悠游悠游,2019-06-04,原文地址:https://yymmss.com/p/rgb-colors.html