我希望“洗掉”我正在应用的图像,就好像我在图像顶部覆盖了一个纯白色层并控制其不透明度。它应该从原始图像褪色为全白图像。
brightness()
过滤器似乎是我想要的。然而,这实际上是将所选因子乘以每个像素,使亮像素变亮,但使已经较暗的像素保持黑暗(当给定的值高于 1 时,如果低于 1,则使亮像素变暗)。
令我惊讶的是缺少在图像顶部覆盖半透明白色的滤镜。我怎样才能通过 CSS
filter
属性实现这一目标?
原创 |
---|
CSS 过滤器,带有
|
CSS 过滤器,带有
|
---|---|
所需(叠加 50% 不透明度白色) | 所需(覆盖 90% 不透明度白色) |
---|---|
--factor: 0.5; /* Should range only between 0 and 1 */
filter: invert(calc(var(--factor) / 2)) brightness(calc(1 + var(--factor)));
这是通过将
brightness()
函数与 invert()
函数组合来实现的,如下所示。诀窍是当所需亮度为 100% 时,让 invert
达到 0.5
,并让 brightness
达到 2
。结果非常接近所需的滤镜,即使 --factor
参数在 0 到 1 之间进行动画处理,也应该足以产生视觉上预期的结果。
解决方案在
|
解决方案在
|
---|---|
观察
invert(0.5)
生成全灰色图像,其中每个像素都位于其逆向路径的中间,这意味着它们都在 0.5(中灰色)处相遇。运行以下代码片段以获取 invert(factor / 2)
。在invert(1 / 2)
处,此操作的结果是将黑色、中间色调和白色全部映射到中灰色。
但我们实际上想要将 blacks、midtones 和 whites 映射到 white,这正是双中灰色。由于
brightness()
只是将每个像素乘以其给定值,因此我们可以使用 brightness(2)
将像素加倍。运行以下代码片段以获取 brightness(1 + factor)
。
将这两个函数组合在一起,我们首先将路径上的每个像素映射到中间灰色,然后将其加倍到白色。
document.addEventListener("DOMContentLoaded", () => {
const img = document.querySelector("img");
const input = document.querySelector("input");
const update = () => document.body.style.setProperty("--factor", input.value);
update();
input.addEventListener("input", update);
});
#invert:checked ~ img {
filter: invert(calc(var(--factor) / 2));
}
#brightness:checked ~ img {
filter: brightness(calc(1 + var(--factor)));
}
#combined:checked ~ div img {
filter: invert(calc(var(--factor) / 2)) brightness(calc(1 + var(--factor)));
}
#ground-truth:checked ~ div::after {
content: "";
background: rgba(255, 255, 255, var(--factor));
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
div {
display: inline-block;
position: relative;
}
<label><code>factor</code>:</label>
<input type="range" min="0" max="1" step="any" value="0.5" /><br />
<input type="radio" name="choice" id="invert" value="invert" />
<label for="invert"><code>invert(factor / 2)</code></label><br />
<input type="radio" name="choice" id="brightness" value="brightness" />
<label for="brightness"><code>brightness(1 + factor)</code></label><br />
<input type="radio" name="choice" id="combined" value="combined" checked />
<label for="combined"><code>invert(factor / 2) brightness(1 + factor)</code> (approximate filter)</label><br />
<input type="radio" name="choice" id="ground-truth" value="ground-truth" />
<label for="ground-truth">desired ground truth (correct filter)</label><br />
<div>
<img src="https://i.sstatic.net/k53TSb8R.png" alt="Test image" style="display: block" />
</div>
为了一些有趣的数学探索,我分析了所需滤波器和近似滤波器之间的误差。
结果通常与图像上白色的线性插值相关,但方程并不完全相同。
所需滤波器的方程为:
f(factor, pixel) = (pixel) - (pixel)(factor) + (factor)
近似滤波器的方程为:
f(factor, pixel) = (pixel) + (0.5 - pixel)(factor)(factor) + (0.5)(factor)
从技术上讲,这种近似确实有一个白色值被剪裁的小区域(如下图灰色天花板平面上方所示)。正确滤波器和近似滤波器的比较(作为所选因子和输入像素通道亮度的函数)可以在此 3D 图中看到:https://www.desmos.com/3d/ldxipd3j1n
Z = 1