Reputation: 8137
Problem: We have a video which is used to help brand our website. It's a simple video which is just made of a pattern of of shapes changing their illuminance. We have been able to turn this into black and white and were hoping from this video we would be able to change this to be blue and white for example, or red and white. As we have different applications which will have the same pattern video but with different color. I was hoping there would be a way to do this in CSS filters. If there is another way of doing this, I am all ears, ideally this would be automated as to not require somebody to open up some software and load the video and edit it there.
Upvotes: 0
Views: 500
Reputation: 137044
There is this Q/A which goes in very good explanations about how to change from one color to an other using built-in CSS blending filters.
But unfortunately, these will also affect your white pixels.
So to do it, you'll need a smarter filter than the ones proposed as built-ins by CSS specs: SVG ones.
There might be a lot of different ways to do it, but I'll try to keep it simple here and use at the maximum built-ins.
feColorMatrix[type="luminanceToAlpha"]
allows us to create an alpha blending based on the luminance of the source graphic we passed in.
This is exactly the inverse of what we want: it converts all white pixels to transparent ones.
So we have to add a small compositing operation to our filter, so that we keep only these white pixels.
Now we have a transparent video, with only the luminescent pixels painted (only white in case of true Black&White).
So all we have to do is to set a background color of our choice, and everything that was black, will now be set to this color. However, since the filter will affect the <video>
element, we need to wrap it in a container element, which won't be affected by this filter.
// since filter affects the whole <video> element,
// we set the replacing color as the background color of a wrapping element
col.oninput = e => wrapper.style.backgroundColor = col.value;
#vid {
filter: brightness(250%) url('#darkToAlpha');
width: 100%;
}
#wrapper {
margin: 0;
padding: 0;
display: inline-block;
line-height: 0;
background: black; /* :P */
}
<label>Select a color: <input type="color" id="col"></label>
<p id="wrapper">
<video id="vid" controls muted src="https://upload.wikimedia.org/wikipedia/commons/6/64/Plan_9_from_Outer_Space_%281959%29.webm#t=56:13"></video>
</p>
<svg width="100%" height="100%">
<filter id="darkToAlpha">
<!-- this makes luminance transparent -->
<feColorMatrix in="SourceGraphic"
type="luminanceToAlpha" result="lum"/>
<!-- so invert it using compositing -->
<feComposite in="SourceGraphic" in2="lum" operator="in"/>
</filter>
</svg>
Note that it doesn't work perfectly for grayscale images, luminanceToAlpha takes a bit too wide range, and this is why I also added a brightness()
filter.
Upvotes: 2