Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching a color in SVG with feColorMatrix

I created a drop shadow in SVG using SourceAlpha for the shadow, so its plain black. Using feColorMatrix I reduced the opacity a bit, but still it wasn't looking as I wanted - I want the color of the shadow to match a specific color value. So I took a more in depth look at feColorMatrix.

Now I don't use SourceAlpha as source for the shadow, but SourceGraphic. As my vector image is plain white aka rgba(255, 255, 255, 1), I can calculate the color of the shadow like that:

<feColorMatrix in="the-shadow" result="color-out" type="matrix"
                values="0.0157 0      0      0 0
                        0      0.3059 0      0 0 
                        0      0      0.7765 0 0 
                        0      0      0      1 0  "/>

The outcome should be a dark blue shadow aka rgba(4, 78, 198, 1).

Actually this is working and I believe the calculations are all correct, but when creating a shadow with CSS3 using the same color, there is a noticeable difference: The SVG filter seems to render the color a bit too light. Is there any way to fix that?

like image 334
Sven Avatar asked Feb 02 '13 15:02

Sven


2 Answers

feColorMatrix like most filters operates in the linearRGB colour space. If you want an sRGB colour, Try setting color-interpolation-filters="sRGB" as an attribute on the feColorMatrix.

    <svg width="100%" xmlns:xlink="http://www.w3.org/1999/xlink"
    
    viewBox="0 0 640 480" height="100%"
    xmlns="http://www.w3.org/2000/svg">
    
    <filter id="cm">
    
    <feColorMatrix in="SourceGraphic" type="matrix"
                    values="0.0157 0      0      0 0
                            0      0.3059 0      0 0 
                            0      0      0.7765 0 0 
                            0      0      0      1 0  "/>
    
    </filter>
    
    <filter id="cmRGB">
    
    <feColorMatrix color-interpolation-filters="sRGB" in="SourceGraphic" type="matrix"
                    values="0.0157 0      0      0 0
                            0      0.3059 0      0 0 
                            0      0      0.7765 0 0 
                            0      0      0      1 0  "/>
    
    </filter>
    
    <rect width="100%" height="50%" fill="white" filter="url(#cm)"/>
    
    <rect y="50%" width="100%" height="100%" fill="white" filter="url(#cmRGB)"/>
    
    </svg>

It sure looks different to me on Firefox.

like image 146
Robert Longson Avatar answered Nov 15 '22 16:11

Robert Longson


Whilst my answer repeats the same idea, what I have to add is too much for a comment.

I don't know for sure, what is linearRGB in the standard, but I expect it to be, erm, linear. I.e. white color transformed with (darken-twice)

R | ½ 0 0 0 0
G | 0 ½ 0 0 0
B | 0 0 ½ 0 0
A | 0 0 0 1 0

should result in the same color as rgb(50%, 50%, 50%), shouldn't it?

As well as black color transformed with (ligthen-twice)

R | ½ 0 0 0 ½
G | 0 ½ 0 0 ½
B | 0 0 ½ 0 ½
A | 0 0 0 1 0

expected to be the same 50% gray.

But what I actually see as a result is much lighter than expected, color picker shows #BCBCBC instead of #808080. On the other hand, color-interpolation-filters="sRGB" makes the result correct (checked a macbook and a win10 ASUS notebook with default settings).

https://jsfiddle.net/7wvy57fq/2/

like image 1
kirilloid Avatar answered Nov 15 '22 17:11

kirilloid