svg-filters - 如何计算线性RGB颜色空间中feComponentTransfer的离散函数中的步骤
问题描述
我正在尝试使用这样的 feComponentTransfer 函数制作离散渐变:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg x="0" y="0" width="500px" height="120px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>A discrete gradient</title>
<defs>
<linearGradient id="inputImage" gradientUnits="objectBoundingBox" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0" stop-color="black"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<filter id="discrete" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%" color-interpolation-filters="linearRGB">
<feComponentTransfer>
<feFuncR type="discrete" tableValues=".666667 .6 .533333 .466667 .4 .333333 .266667 .2 .133333 .066667"/>
<feFuncG type="discrete" tableValues=".666667 .6 .533333 .466667 .4 .333333 .266667 .2 .133333 .066667"/>
<feFuncB type="discrete" tableValues=".933333 .866667 .8 .733333 .666667 .6 .533333 .466667 .4 .333333"/>
</feComponentTransfer>
</filter>
</defs>
<rect x="10px" y="10px" width="480px" height="100px" fill="url(#inputImage)" filter="url(#discrete)"/>
</svg>
我期待看到这些颜色:#AAAAEE、#9999DD、#8888CC、#7777BB、#6666AA、#555599、#444488、#333377、#222266、#111155,但 Firefox* 显示了这些颜色:#D5D5F7、#分别为 CBCBEF、#C1C1E7、#B6B6DE、#AAAAD5、#9C9CCB、#8D8DC1、#7C7CB6、#6666AA、#49499C,它们提供了类似的混合,但更亮了一些色调。我知道这个滤镜的工作是调整亮度、对比度等。但是我不明白在这种情况下它是如何工作的。所以,这里的问题是我应该如何计算 tableValues 中的步骤 - 在 linearRGB 颜色空间内 - 以便准确显示我想要的颜色。
我注意到显示(输出)颜色的大多数组件值都完全映射到给定范围之外,我想知道 - 如果我错了,请纠正我 - 这与规范有何一致。
由于我不了解这些函数在线性RGB 颜色空间中是如何工作的,所以我决定手动获取我想要的颜色。我尝试了随机值,经过数千次尝试,我终于找到了前 6 种所需颜色(#AAAAEE、#9999DD、#8888CC、#7777BB、#6666AA、#555599)和第九种颜色(#222266)的步骤。对于第七种所需颜色(#444488, R:68|0.266667, G:68|0.266667, B:136|0.533333),我很容易找到了 feFuncB 步骤,但找不到红色和绿色函数的值来精确输出 68| 0.266667。因此,最接近所需的 #444488 给了我红色和绿色的值 0.058823,它输出了接近 #454588 的值。对于所需的第 8 种(#333377)和第 10 种(#111155)颜色,我也遇到了同样的问题,我可以实现的最接近的输出分别是 #353577 和 #0D0D55。
<feFuncR type="discrete" tableValues=".4 .317647 .247058 .184313 .133333 .09 .058823 .0353 .015686 .0039"/> <feFuncG type="discrete" tableValues=".4 .317647 .247058 .184313 .133333 .09 .058823 .0353 .015686 .0039"/> <feFuncB type="discrete" tableValues=".8588 .721568 .603921 .498039 .4 .317647 .247 .184313 .13333 .09"/>
现在我重复这个问题:有没有一种简单的方法(数学类型、乘数或其他东西)来显示指定的颜色,而不浪费时间测试随机小数?
- 结果来自 Ubuntu 16.4 64 位 Gnome 上的 Firefox 60.0.2,使用 Gpick 工具进行检查,并且如您所知,与相同或其他操作系统上的其他渲染引擎不同。目前我只对它的工作方式感兴趣,或者更好的是,它应该如何工作。
提前致谢
斯皮罗斯·安德雷达基斯
解决方案
在我回答之前,你需要非常小心你的吸管告诉你的是颜色值。如果您想在标准 sRGB 或 linearRGB 空间中获得特定颜色,请确保您的吸管设置为该空间。
也就是说,如果您要在 linearRGB 中进行转换,但您希望在 sRGB 中获得特定颜色作为结果,那么您需要在 linearRGB 术语中指定目标 sRGB 颜色的等价物。您可以使用伽马校正公式来做到这一点。
例如,如果您希望渐变中的第一种颜色是 sRGB 中的#AAAAEE,那么您必须对数组输入进行以下校正(十进制):
linearRGB 中的颜色 = ((sRGB 中的颜色+0.055)/1.055)^2.4
因此,例如,组件传输数组中的第一个 R/G/B 值应该是
R : 0.402 = ((.6667 + 0.055)/1.055)^2.4
G : 0.402 = ((.6667 + 0.055)/1.055)^2.4
B : 0.855 = ((.9333 + 0.055)/1.055)^2.4
这个公式通常不是 100% 准确的 - 当 sRGB 单位值小于 0.04045 (L=S/12.92) 时,您需要使用不同的公式。但是你所有的目标值都在 0.04 以上,所以我们不用担心。
完整结果:
<svg x="0" y="0" width="500px" height="120px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>A discrete gradient</title>
<defs>
<linearGradient id="inputImage" gradientUnits="objectBoundingBox" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0" stop-color="black"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<filter id="discrete" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
<feComponentTransfer>
<feFuncR type="discrete" tableValues="0.4020 0.3185 0.2462 0.1845 0.1329 0.0908 0.0578 0.0331 0.0160 0.0056"/>
<feFuncG type="discrete" tableValues="0.4020 0.3185 0.2462 0.1845 0.1329 0.0908 0.0578 0.0331 0.0160 0.0056"/>
<feFuncB type="discrete" tableValues="0.8550 0.7231 0.6038 0.4969 0.4020 0.3185 0.2462 0.1845 0.1329 0.0908"/>
</feComponentTransfer>
</feComponentTransfer>
</filter>
</defs>
<rect x="10px" y="10px" width="480px" height="100px" fill="url(#inputImage)" filter="url(#discrete)"/>
</svg>
推荐阅读
- python - Python加速JSON解析——自带解码器
- opencv - 在一行中识别具有不同字符高度的俄罗斯车牌 OpenALPR
- angular - @Optional() @Host() 抛出“无法实例化循环依赖!” 错误
- java - 在使用 var 的循环中进行类型推断
- android - Firebase 项目最大应用数
- ios - 翻转superview后UIButton点击区域正在移动
- bash - 在文件的最后一行添加一个点
- java - 如何让一个红色框出现在变量名之外,以便在我在 java netbeans 中使用它的所有地方更改它?
- angular - 从抽象类继承存在依赖注入问题
- javascript - 反应 - 默认状态