首页 > 解决方案 > 如何计算线性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>
  1. 我期待看到这些颜色:#AAAAEE、#9999DD、#8888CC、#7777BB、#6666AA、#555599、#444488、#333377、#222266、#111155,但 Firefox* 显示了这些颜色:#D5D5F7、#分别为 CBCBEF、#C1C1E7、#B6B6DE、#AAAAD5、#9C9CCB、#8D8DC1、#7C7CB6、#6666AA、#49499C,它们提供了类似的混合,但更亮了一些色调。我知道这个滤镜的工作是调整亮度、对比度等。但是我不明白在这种情况下它是如何工作的。所以,这里的问题是我应该如何计算 tableValues 中的步骤 - 在 linearRGB 颜色空间内 - 以便准确显示我想要的颜色。

  2. 我注意到显示(输出)颜色的大多数组件值都完全映射到给定范围之外,我想知道 - 如果我错了,请纠正我 - 这与规范有何一致。

  3. 由于我不了解这些函数在线性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"/>

现在我重复这个问题:有没有一种简单的方法(数学类型、乘数或其他东西)来显示指定的颜色,而不浪费时间测试随机小数?

提前致谢

斯皮罗斯·安德雷达基斯

标签: svg-filters

解决方案


在我回答之前,你需要非常小心你的吸管告诉你的是颜色值。如果您想在标准 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>


推荐阅读