还原过滤器invert()CSS规则

时间:2018-02-11 11:45:58

标签: css css-filters

我有一整段代码,其中应用了CSS规则scikit-learn

在这个区块中,我有一个图像,当然也遵循这个CSS规则,然后被反转。

我需要为此图片恢复此flow

有可能吗?我尝试了filter: invert(0.85),但图片并不像以前那样完全,它仍然有点倒置(由于第一个invert()只是invert(1)而不是{{1 }})

见这个例子:

invert
0.85

3 个答案:

答案 0 :(得分:7)

TL; DR

您无法通过应用其他invert()或其他过滤器的组合来恢复invert()过滤器。

首先,我将从一个基本示例和解释开始:invert()过滤器用于通过指定反转的百分比(或从0到{的值来反转颜色{1}})。如果我们使用值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;
}




从这个例子中我们也可以理解反转是如何处理颜色的。对于 RGB 的每个值,我们只需<div class="container" style="filter:invert(1)"> <div class="inner"></div> <div class="inner" style="filter:invert(1)"></div> </div>

现在让我们考虑另一个值的反转,让我们来看(255 - x)

&#13;
&#13;
0.85
&#13;
.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;
}
&#13;
&#13;
&#13;

它是如何运作的?

对于第一种颜色<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 xy现在让我们使用 f(x) 表达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计算的常量。我们可以区分3种情况:

  1. 0.5的值等于[1,+infinity]时,函数没有定义,因此反转不能被反转(顺便说一句,你可以尝试应用反转(0.5)来看结果)
  2. 当p的值大于0.5时,K是[-infinity,-1]范围内的值。
  3. 当p的值小于K时,K是K=1/K'范围内的值。
  4. 因此,如果我们省略第一种情况,[-1,1]/{0}可以这样设置abs(K')其中K&#39}是]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()。我们可能会对某些值进行近似估计,但对于其他值则不可能(例如使用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); }时,我们会丢失一些我们无法回复的信息。例如,当您获得彩色图像时,您会变成黑色和黑色的图像。白色版。你没办法把它换回颜色。

    <强>更新

    这是一些JS代码,以证明上述计算是正确的,并看到一些结果。在使用我的函数时,我使用canvas来再次绘制图像:

    不幸的是我无法在代码段中使用图片来获取安全性和跨浏览器原点问题,所以我考虑了渐变

    &#13;
    &#13;
    <div class="grad"></div>
    <div class="filter">
      <div class="grad"></div>
      <canvas></canvas>
    </div>
    &#13;
    1
    &#13;
    0.5
    &#13;
    &#13;
    &#13;

    正如我们所看到的,我们有3张图片:原始图片倒置图片以及我们应用函数的图片将其恢复为原始图片

    我们在这里取得了不错的成绩,因为该值接近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); }的另一个值会产生错误的结果,因为我们接近函数定义的限制:

    &#13;
    &#13;
    <div class="grad"></div>
    <div class="filter">
      <div class="grad"></div>
      <canvas></canvas>
    </div>
    &#13;
    invert()
    &#13;
    p
    &#13;
    &#13;
    &#13;

    您可以使用此代码创建一个通用函数,以便部分还原canvas过滤器:

    1. 使用某些JS,您可以轻松找到过滤器中使用的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, 150); var grd2 = ctx.createLinearGradient(0, 0, 0, 150); grd2.addColorStop(0, "green"); grd2.addColorStop(1, "yellow"); ctx.fillStyle = grd2; ctx.fillRect(40, 0, 70, 150); } var invert = function(p) { //we get the data of the image var imgData = canvas.getContext('2d').getImageData(0, 0, 150, 150); 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); })的值。
    2. 您可以使用特定的选择器仅定位要应用此逻辑的特定图像。
    3. 正如您所看到的,我创建了一个body { margin: 0; } div, canvas { display: inline-block; } .grad { height: 150px; width: 150px; background: linear-gradient(to bottom, green, yellow)40px 0/70px 100% no-repeat, linear-gradient(to right, blue, red); },因此想法是创建它,然后隐藏图像以仅保留画布。
    4. 这是一个更具互动性的演示:

      &#13;
      &#13;
      <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></canvas>
      </div>
      <p>Adjust the value of the invert filter</p>
      <input type="range" value="0" min=0 max=1 step=0.05>
      &#13;
      0.5
      &#13;
      0.5
      &#13;
      &#13;
      &#13;

      从这个演示中我们还可以注意到,当我们接近值K时,我们不能仅仅因为过滤器不能在K'处反转而且如果我们引用对于先前的计算,{{1}}的值变得非常大,因此{{1}}太小。

答案 1 :(得分:1)

您需要使用其他CSS filter()的组合来还原更改。根据应用的初始filter(),这可能非常困难。

在这种特殊情况下,只应用invert(0.85),我们可以尝试其他一些filter()来恢复图像。

通过一些实验,看起来以下内容将起作用:

filter: invert(1) contrast(1.3) saturate(1.4);

这是一个粗略的猜测,但在视觉上似乎可以做到这一点。

.flex {
  width: 100%;
  display: flex;
}

img {
  width: 100%;
  display: block;
}

.flex > div{
  flex: 1;
}

.filter {
  filter: invert(0.85);
}

.filter img {
  filter: invert(1) contrast(1.3) saturate(1.4);
}

p {
  color: red;
}
<div class="flex">
  <div class="initial">
    <p>Some red text</p>
    <img src="https://s7d1.scene7.com/is/image/PETCO/cat-category-090617-369w-269h-hero-cutout-d?fmt=png-alpha" alt="">
  </div>
  <div class="filter">
    <p>Some red text</p>
    <img src="https://s7d1.scene7.com/is/image/PETCO/cat-category-090617-369w-269h-hero-cutout-d?fmt=png-alpha" alt="">
  </div>
</div>

答案 2 :(得分:1)

其他答案表明使用CSS实现这一目标很困难。这是一个您可能会觉得有用的基本JavaScript方法。您检测到.filter是否包含图片,如果包含图片,则删除该课程filter

var filteredDiv = document.querySelectorAll(".filter"),
  len = filteredDiv.length,
  i;

for (i = 0; i < len; i++) {
  if (filteredDiv[i].getElementsByTagName('img').length > 0) {
    filteredDiv[i].classList.remove('filter');
  }
}
body {
  font-size: 0;
}

.filter {
  filter: invert(.85);
}

div {
  display: inline-block;
  width: 200px;
}

img {
  width: 100%;
  height: auto;
}

div>div {
  background: yellow;
  font-size: 2rem;
}
<div class="filter">
  <img src="https://s7d1.scene7.com/is/image/PETCO/cat-category-090617-369w-269h-hero-cutout-d?fmt=png-alpha" alt="">
</div>
<div class="filter">
  <div>Sample text</div>
</div>