使用Sharp(libvips)实现CSS / SVG对比度过滤器

时间:2019-03-24 11:31:01

标签: svg-filters css-filters sharp

我正在使用libvips在后端上转换图像,并在前端上使用css / svg预览来节省资源。

我正在努力实现对比css / svg过滤器功能。

The specification将对比度显示为线性变换,形式为:

out = slope * in + intercept

其中intercept应该是:

intercept = - (0.5 * slope) + 0.5

这样,我可以在图像修改的CSS预览中使用contrast(1.25)

但是,通过JS库Sharp在libvips中实现此线性函数:

sharp.linear(contrast, - (0.5 * contrast) + 0.5)

更深入地观察图像的对比度变化,预期结果是高点被放置得更高而低点被降低到更低。这看起来像是与规范的矛盾,因为该规范应用了线性变换,因此它应始终是多个并相加,使得高点更高,但低点也更高。

使用线性锐化(在libvips中也是如此)来改变对比度,输出实际上看起来像一个亮度滤镜,在css / svg滤镜的规范中,它是形式线性变换而无需加法

out = slope * in

在我看来,这可能是我误解了SVG线性函数中的截距。同样,比较svg和css也显示出差异。在CSS中使用contrast(2)应该可以在svg中模仿slope = 2intercept = -(0.5 * 2) + 0.5 = -0.5,在这种提琴中不是这样的:

.svg {
  filter: url(#contrast);
}

.css {
  filter: contrast(2);
}
<img src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="svg" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="css" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">

<svg>
  <filter id="contrast">
    <feComponentTransfer>
      <feFuncR type="linear" slope="2" intercept="-0.5"/>
      <feFuncG type="linear" slope="2" intercept="-0.5"/>
      <feFuncB type="linear" slope="2" intercept="-0.5"/>
    </feComponentTransfer>
  </filter>
</svg>

您可以清楚地看到带有svg滤镜的第二张图像看起来与使用css滤镜的第三幅图像不同。

我对过滤器的理解完全错误吗?我希望应该在某个地方有某个阈值,以将乘法转换为低位除法。

如何在不同的环境中将CSS对比度实现为具有相同结果的线性函数?

2 个答案:

答案 0 :(得分:1)

您的直觉是不正确的:)对于小于0.5的输入值-公式会降低亮度-为什么?对比值为2,输入值为0.4

输出= 2 * 0.4-(0.5 * 2)+ 0.5

输出= 0.8-1 + 0.5

输出= 0.3

如您所见,当输入低于0.5时,输出将始终小于输入,因为斜率分量与截距的第一个(负)分量之和等于对比度乘以通过输入与0.5之差

这是单位值上的公式结果(以0/1为上限和上限)。

enter image description here

默认情况下,CSS滤镜也使用sRGB颜色空间。 SVG滤镜使用linearRGB。您需要通过向svg元素添加属性:color-interpolation-filters =“ sRGB”来将SVG滤镜颜色空间设置为sRGB。当您执行此操作时-您的图像看起来一样。

.svg {
  filter: url(#contrast);
}

.css {
  filter: contrast(2);
}
<img src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="svg" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="css" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">

<svg color-interpolation-filters="sRGB">
  <filter id="contrast">
    <feComponentTransfer>
      <feFuncR type="linear" slope="2" intercept="-0.5"/>
      <feFuncG type="linear" slope="2" intercept="-0.5"/>
      <feFuncB type="linear" slope="2" intercept="-0.5"/>
    </feComponentTransfer>
  </filter>
</svg>

答案 1 :(得分:0)

https://github.com/lovell/sharp/issues/1958

这里有一个来自 css 的工作公式:

filter: `contrast(${contrast})`

锐化:

brightness = 1;
image.linear(brightness * constrast, brightness * (-(128 * contrast) + 128));

虽然,我还没有弄清楚如何将 brightness 合并到这个中