Search code examples
svgsvg-filters

Can I set specific spacing for each value on [tableValues]?


I need to apply a filter as a gradient map to HTML elements, with custom gradients and specific distances between each color value.


Putting into images what I've done and what I'd like to do.

Let's say we have a black & white image.
With some css, we use the filter below to map from black/white to red/green/blue.

<filter id="rgb_gradient">
  <feComponentTransfer>
    <feFuncR type="table" tableValues="1 0 0"/>
    <feFuncG type="table" tableValues="0 1 0"/>
    <feFuncB type="table" tableValues="0 0 1"/>
    <feFuncA type="table" tableValues="0 1"/>
  </feComponentTransfer>
</filter>

Point A to B will look like this: enter image description here

At the moment, all three colors will be evenly distributed (red at 0%, green at 50%, blue at 100%).


So, back to the question...

Can I set/move (for example) the green value from 50% to 82%?

What we should expect: https://i.imgur.com/3qlOztE.png

Thanks in advance.


Solution

  • You can definitely do it. However, achieving the granularity you look for can be a pain.

    First, I would like to take a look at what you are doing. For each component, you are setting three breakpoints. The interpolation evenly divides the [0,1] input region, so you are setting three regions: 0-0.33, 0.34-0.66 and 0.67-1 (please disregard the rounding). You are mapping the red coordinate to dark pixels, since the first value of feFuncR is one and the first values of feFuncG and feFuncB are zero. It is also important to notice that in each region you get an interpolation between the start and the end. That is why you get yellow pixels between red and green, as red fades and green lightens.

    From this, it follows that you can get further control using the same trick with more breakpoints. The problem is that the algorithm will control the actual offsets, so you would may need to set a lot of breakpoints if you want to get something like a 1% error. For instance, this example would give you red from 0 to 0.4, green from 0.4 to 0.8 and blue from 0.8 to 1:

    <filter id="disp" x="0" y="0" width="100%" height="100%">
      <feComponentTransfer>
        <feFuncR type="table" tableValues="1 1 0 0 0"/>
        <feFuncG type="table" tableValues="0 0 1 1 0"/>
        <feFuncB type="table" tableValues="0 0 0 0 1"/>
        <feFuncA type="table" tableValues="0 1"/>
      </feComponentTransfer>
    </filter>
    

    Result of original transformation (center) and new transformation (right)

    As you can see, you lose the details in dark pixels, as every pixel with a value from 0 to 0.4 is completely red. You can use other values betwee zero and one in the offsets to control that behavior.