4

小tip: 了解LinearRGB和sRGB以及使用JS相互转换

 3 years ago
source link: https://www.zhangxinxu.com/wordpress/2017/12/linear-rgb-srgb-js-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.
neoserver,ios ssh client

小tip: 了解LinearRGB和sRGB以及使用JS相互转换

这篇文章发布于 2017年12月18日,星期一,23:11,归类于 Graphic相关, JS相关。 阅读 19615 次, 今日 137 次 一条评论

by zhangxinxu from http://www.zhangxinxu.com/wordpress/?p=6646
本文可全文转载,但需得到原作者书面许可,同时保留原作者和出处,摘要引流则随意。

一、了解LinearRGB和sRGB

LinearRGB顾名思义就是线性RGB颜色。

假设白板的光线反射率是100%,黑板的光线反射率是0%。则在线性RGB的世界中,50%灰色就是光线反射率为50%的灰色。

然而,人这种动物,对于真实世界的颜色感受,并不是线性的,而是曲线的,如下图示意:

人类心理感受与真实亮度对比

横坐标是真实亮度,纵坐标是人的视觉感受。可以看到人对这个世界亮度的感受和实际的反射亮度并不是线性的,而是有着很大差异的。

似乎大家反应很平淡嘛,我们在看下面这个例子,下图是一个从白色到黑色的渐变,于是很自然的,我们会认为中间的位置就是50度灰,也就是俗称的中灰:

纯黑到纯白

然而这仅仅是我们的视觉感受是中灰,如果我们把这个灰色放到自然世界里,其物理亮度值大约在白色块的21%左右,其实已经是相当黑了

从进化论上讲,可能与人类是日行性动物有关。

由于人类直觉判断遵循眼见为实,如果我们的显示器设备,全部都是按照LinearRGB来渲染,则会和我们真实世界看到的颜色有差异。这个问题在以前是非常严重的,老的显示器这种物理器件显示颜色是线性的,纯白纯黑,然后线性调节亮度颜色就出来的。但人的真实视觉确实非线性的,这就导致电脑看到一张服装图片是这样子的,结果现实世界买回来是另外一个样子。

为了让我们的显示器显示的效果,更接近于我们真实的视觉感受,微软联合爱普生、HP惠普重新制定的一套非线性的彩色语言协议,就是这里的sRGB。目前我们使用的各类设备显示器颜色全部都是基于sRGB显示的。

好了,看样子现在sRGB已经一统天下了,那还有LinearRGB线性RGB什么事情呢?

那就是LinearRGB在图形图像处理上有着天然的优势。

因为其颜色是线性有明显规律的,在数学处理上就非常简单。

比方说你让一个普通图像和一个半透明图像相加,或者进行2D混合或3D阴影或者几乎任何图像处理,你肯定是强烈希望采用的是一个线性的颜色空间,因为计算要简单太多了。什么反向,提亮等效果都不在话下。

于是,在SVG或者webGL等与图形处理相密切的语言领域,很多属性或者颜色处理,都是基于LinearRGB来实现的。

例如SVG滤镜中的color-interpolation-filters属性其默认值就是LinearRGB,并且Safari浏览器仅支持LinearRGB。

这就给我们的实际开发带来了一定的阻碍,比如说当我们对设计软件进行做图的时候,我们的RGB颜色的选取肯定是基于显示器颜色,但这个颜色往往在LinearRGB那里就不准确了。

举例说明:

sRGB世界中,RGB色值范围是0~255,中灰色就是127,使用0~1范围表示就是0.5,但是,转换成LinearRGB就是0.214

也就是说图像处理的时候,你以为你使用了一个中灰色,实际上使用的是一个深灰色。

如何避免这种问题呢?

那就是根据需要的颜色空间进行转化。

二、LinearRGB和sRGB使用JS相互转换

这里的转化使用0到1范围示意。

LinearRGB转换为sRGB:

var linear = xxx;  // xxx是0-1的数值
var s;
if (linear <= 0.0031308) {
  s = linear * 12.92;
} else {
  s = 1.055 * Math.pow(linear, 1.0/2.4) - 0.055;
}

sRGB转换为LinearRGB:

var s = xxx;    // xxx是0-1的数值
var linear;
if (s <= 0.04045) {
  linear = s / 12.92;
} else {
  linear = Math.pow((s + 0.055) / 1.055, 2.4);
}

使用示意
假设我们的SVG的滤镜使用的颜色空间是LinearRGB,我们希望颜色最后的计算值是0.5,请问,我们应该输入的sRGB值是多少?

套用LinearRGB转换为sRGB代码,于是有:

s = 1.055 * Math.pow(0.5, 1.0/2.4) - 0.055 = 0.7353569830524495

如果将其计算值转化成十进制的颜色表示,则有:

Math.floor(0.7353569830524495 * 256) = 188

也就是显示器上的188颜色才对应LinearRGB的0.5

也就是rgba(188,188,188)才是线性RGB世界的中灰色,而不是rgba(127,127,127)

三、结束语

搜索了一下,中文相关的资料其实并不多,所以本文内容还是有必要的,虽然说内容比较小众,受众有限,但对于需要的人讲,可能就是雪中送炭的重要资料了。

本文两张示意图参考自“色彩校正中的 gamma 值是什么?”这个问题的这个回答,这里表示感谢。

本文内容也是边学习边整理的,如果有表述不对的地方,请大力指正!

14.png

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

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:http://www.zhangxinxu.com/wordpress/?p=6646


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK