TL;DR
您无法通过应用另一个 invert() 或其他过滤器的组合来还原 invert() 过滤器。
首先,我将从一个基本示例和解释开始:invert() 过滤器用于通过指定反转百分比(或从0 到1 的值)来反转颜色。如果我们使用值1,我们会完全反转颜色,因此很容易回到初始状态,因为我们只需再次应用相同的反转:
.container {
display:flex;
justify-content:space-around;
}
.inner {
height: 200px;
width: 200px;
background:
linear-gradient(to right, rgb(255,0,0) 50%, rgb(0,255,255) 0) 0 0/100% 50% no-repeat,
linear-gradient(to right, rgb(50,0,60) 50%, rgb(205,255,195) 0) 0 100%/100% 50% no-repeat;
}
<div class="container" style="filter:invert(1)">
<div class="inner"></div>
<div class="inner" style="filter:invert(1)"></div>
</div>
从这个例子中,我们还可以了解反转是如何处理颜色的。我们只需为 RGB 的每个值执行(255 - x)。
现在让我们考虑另一个值的反转,让我们采用0.85:
.container {
display: inline-block;
}
.inner {
display: inline-block;
height: 200px;
width: 200px;
background: linear-gradient(to right, rgb(255, 0, 0) 50%, rgb(0, 255, 255) 0) 0 0/100% 50% no-repeat, linear-gradient(to right, rgb(50, 0, 60) 50%, rgb(205, 255, 195) 0) 0 100%/100% 50% no-repeat;
}
<div class="container" style="filter:invert(0.85)">
<div class="inner"></div>
</div>
<div class="inner"></div>
它是如何工作的?
对于第一种颜色(rgb(255,0,0)),我们得到这个(rgb(38, 217, 217)),所以计算如下:
255 - [255*(1-0.85) + x*(2*0.85-1)]
所以我们的目标是反转这个公式:
f(x) = 255 - [255*(1-p) + x*(2*p-1)] , p a value in the range [0,1]
您可能清楚地注意到,当p=0 时我们将拥有f(x)=x 和p=1 时我们将拥有f(x)=255-x,这非常容易。现在让我们用 f(x) 来表达x 的值(我这里用y):
x = 1/(2*p-1) * [255 - (255*(1-p) +y)]
让我们试着让它类似于一个反转函数。让我们拥有y=(2*p-1)*y',我们将获得:
x = 1/(2*p-1) * [255 - (255*(1-p) +(2*p-1)*y')]
相当于
x = 1/(2*p-1) * f(y') ---> x = K * f(K*y) with K = 1/(2*p-1)
这里f 是使用p 相同值的反转函数,K 是基于值p 计算的常数。我们可以区分三种情况:
- 当
p 的值等于0.5 时,函数没有定义,因此不能反转(你可以顺便尝试应用 invert(0.5) 来查看结果)
- 当p的值大于
0.5时,K是[1,+infinity]范围内的正值。
- 当p的值小于
0.5时,K是[-infinity,-1]范围内的负值。
所以如果我们省略第一种情况,K 可以这样设置K=1/K',其中 K' 是[-1,1]/{0} 范围内的值,abs(K') 是]0,1] 范围内的值。那么我们的函数可以写成如下:
x = (1/K') * f(y/K') where K' in the range [-1,1] define by (2*p - 1)
此时,我们使用invert 函数和乘法/除法来表达我们的函数,该值具有我们可以轻松计算的值。
现在我们需要找出哪个过滤器应用乘法/除法。我知道有使用线性变换的brightness 和contrast 过滤器。
如果我们使用brightness(p),论坛如下:
f(x) = x*p;
如果我们使用contrast(p),公式将如下所示:
f(x) = p*(x - 255/2) + 255/2
这将在这里结束......
正如最初所说,我们无法使用其他过滤器还原invert()。对于某些值,我们可能可以近似此值,但对于其他值则不可能(例如 0.5)。换句话说,当应用invert() 时,我们会丢失一些我们无法找回的信息。就像,例如,当您将彩色图像转换为黑白版本时。你无法恢复最初的颜色。
更新
这里有一些JS代码来证明上面的计算是正确的,并看看一些结果。在应用我的功能时,我使用画布再次绘制图像:
不幸的是,我不能在 sn-p 中使用图像来解决安全性和跨浏览器来源问题,所以我考虑了渐变
var canvas = document.querySelector('canvas');
var img = document.querySelector('img');
var ctx = canvas.getContext('2d');
//we draw the same image on the canvas (here I will draw the same gradient )
//canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
var grd = ctx.createLinearGradient(0, 0, 150, 0);
grd.addColorStop(0, "blue");
grd.addColorStop(1, "red");
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 150, 150);
//we get the data of the image
var imgData = canvas.getContext('2d').getImageData(0, 0, 150, 150);
var pix = imgData.data;
var p = 0.85;
// Loop over each pixel and apply the function
for (var i = 0, n = pix.length; i < n; i += 4) {
pix[i + 0] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 0])));
pix[i + 1] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 1])))
pix[i + 2] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 2])))
// i+3 is alpha (the fourth element)
}
//Draw the image again
imgData.data = pix;
canvas.getContext('2d').putImageData(imgData, 0, 0);
body {
font-size: 0;
}
div,
canvas {
display: inline-block;
}
.grad {
height: 150px;
width: 150px;
background: linear-gradient(to right, blue, red);
}
.filter {
filter: invert(0.85);
}
<div class="grad"></div>
<div class="filter">
<div class="grad"></div>
<canvas></canvas>
</div>
如我们所见,我们有 3 张图像:原始图像、倒置的图像以及我们应用函数使其变回原始图像的图像.
我们在这里取得了不错的结果,因为该值接近1。如果我们使用更接近0.5 的另一个值,则会产生不好的结果,因为我们已经接近定义函数的位置:
var canvas = document.querySelector('canvas');
var img = document.querySelector('img');
var ctx = canvas.getContext('2d');
//we draw the same image on the canvas (here I will draw the same gradient )
//canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
var grd = ctx.createLinearGradient(0, 0, 150, 0);
grd.addColorStop(0, "blue");
grd.addColorStop(1, "red");
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 150, 150);
//we get the data of the image
var imgData = canvas.getContext('2d').getImageData(0, 0, 150, 150);
var pix = imgData.data;
var p = 0.6;
// Loop over each pixel and apply the function
for (var i = 0, n = pix.length; i < n; i += 4) {
pix[i + 0] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 0])));
pix[i + 1] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 1])))
pix[i + 2] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 2])))
// i+3 is alpha (the fourth element)
}
//Draw the image again
imgData.data = pix;
canvas.getContext('2d').putImageData(imgData, 0, 0);
body {
font-size: 0;
}
div,
canvas {
display: inline-block;
}
.grad {
height: 150px;
width: 150px;
background: linear-gradient(to right, blue, red);
}
.filter {
filter: invert(0.6);
}
<div class="grad"></div>
<div class="filter">
<div class="grad"></div>
<canvas></canvas>
</div>
您可以使用此代码创建一个通用函数,让您部分恢复invert()过滤器:
- 使用一些 JS 可以很容易地找到过滤器中使用的
p 的值。
- 您可以使用特定的选择器仅针对要应用此逻辑的特定图像。
- 如您所见,我创建了一个
canvas,因此我们的想法是创建它,然后隐藏图像以仅保留画布。
这是一个更具交互性的演示:
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var init = function() {
var grd = ctx.createLinearGradient(0, 0, 150, 0);
grd.addColorStop(0, "blue");
grd.addColorStop(1, "red");
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 150, 100);
var grd2 = ctx.createLinearGradient(0, 0, 0, 150);
grd2.addColorStop(0, "green");
grd2.addColorStop(1, "yellow");
ctx.fillStyle = grd2;
ctx.fillRect(40, 0, 70, 100);
}
var invert = function(p) {
//we get the data of the image
var imgData = canvas.getContext('2d').getImageData(0, 0, 150, 100);
var pix = imgData.data;
// Loop over each pixel and apply the function
for (var i = 0, n = pix.length; i < n; i += 4) {
pix[i + 0] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 0])));
pix[i + 1] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 1])))
pix[i + 2] = Math.round((1 / (2 * p - 1)) * (255 - (255 * (1 - p) + pix[i + 2])))
// i+3 is alpha (the fourth element)
}
//Draw the image again
imgData.data = pix;
canvas.getContext('2d').putImageData(imgData, 0, 0);
}
init();
$('input').change(function() {
var v = $(this).val();
$('.filter').css('filter', 'invert(' + v + ')');
init();
invert(v);
})
p {
margin: 0;
}
div,
canvas {
display: inline-block;
}
.grad {
height: 100px;
width: 150px;
background: linear-gradient(to bottom, green, yellow)40px 0/70px 100% no-repeat, linear-gradient(to right, blue, red);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="grad"></div>
<div class="filter">
<div class="grad"></div>
<canvas height="100" width="150"></canvas>
</div>
<p>Adjust the value of the invert filter</p>
<input type="range" value="0" min=0 max=1 step=0.05>
从这个演示中我们还可以注意到,当我们接近值 0.5 时,我们不会得到一个好的结果,这仅仅是因为过滤器不能在 0.5 处反转,如果我们参考之前的计算,值的K 变得非常大,因此K' 太小了。