7

In CSS, when you apply

filter: invert(1) hue-rotate(180deg)

to an image, the color red turns into peachy-pink.

Why is this, and what can be done to use CSS to invert an image and still have red look like red?

Example:

RGB image normal

The same image with filter: invert(1) hue-rotate(180deg) applied:

RGB image inverted and with hue rotated 180 degrees


Update:

It was recommended in the initial answer to apply the above filter to the html element and then also apply it the image. The colors still look off. Here is the result:

RGB image with filter applied to both HTML element and image

1 Answer 1

9

To understand the why we need to perform some math.

If we start with the invert(1) (the easiest one) we will use f(x) = (255 - x)ref. So rgb(255,0,0) will become rgb(0,255,255)

For the hue-rotate(180deg) it's more complex. Considering the specification we will get the following matrix:

-0.574  1.43  0.144
 0.426  0.43  0.144
 0.426  1.43 -0.856

So we will have

R' =  -0.574*R  1.43*G  0.144*B = 1.43*255 + 0.144*255 = 401.37
G' =   0.426*R  0.43*G  0.144*B = 0.43*255 + 0.144*255 = 146.37
B' =   0.426*R  1.43*G -0.856*B = 1.43*255 - 0.856*255 = 146.37

Then a final color rgb(255,146.37,146.37) which is not a red one

html {
  background: rgb(255, 146.37, 146.37)
}


what can be done to use CSS to invert an image and still have red look like red?

It depends on what result you want to get considering the other colors but you can add a staturate() filter to get back your red color:

img {
 filter: invert(1) hue-rotate(180deg) saturate(10);
}
<img src="https://i.sstatic.net/jikdT.png">

Again some Math to understand what is happening. From the same specification and after some simplication we will have the following matrix:

 7.87  -7.15 -0.72
-2.13   2.85 -0.72
-2.13  -7.15  9.28

So

 R' =  7.87*R  -7.15*G -0.72*B =  7.87*255 - 7.87*146.37 = bigger than 255
 G' = -2.13*R   2.85*G -0.72*B = -2.13*255 + 2.13*146.37 = negative
 B' = -2.13*R  -7.15*G  9.28*B = -2.13*255 + 2.13*146.37 = negative

A final color rgb(255,0,0)

3
  • Wow, Temani, that is a truly amazing answer. Thank you. I wrote the question for red to keep things simple. I honestly didn't expect such an incredible answer. My larger goal is to swap black and white (and anything close to those extremes) while maintaining colour hues. Is there a way to accomplish that? Commented Dec 18, 2020 at 22:56
  • @RockPaperLz-MaskitorCasket well, I would say yes but you need to play a lot with filter function and get the math behind to find the perfect combination to your case. Commented Dec 19, 2020 at 1:06
  • Do it with JS pixel by pixel :DD Commented Dec 13, 2021 at 20:10

Not the answer you're looking for? Browse other questions tagged or ask your own question.