cognify
cognify

Reputation: 57

svg filter calculation resolution

I am applying an svg filter to a series of images and it appears the filter is only using the 4 highest significant bits of the color in its calculations, the rest are ignored and have no impact on the result. Is there a way to force the filter to include all 8 color bits in its calculations.

To illustrate my issue I have created a codepen that builds a set of 256 red cells increasing from 0 to 256 intensity in red only. I then svg filter the cells with a linear scale that multiplies the bit value of the color of each cell by 128.

I should see the first two three cells (bit value 0,1,2) as 0, 128 and 256 intensity red and the rest should be 256 red.

What I see is that everything with a decimal value of less than 8 is 0 intensity.

This demonstrates that the first three bits are being ignored in the svg calculation. Why is this the case.

https://codepen.io/jgbgy/pen/LmVGxG

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Threshold</title>
</head>
<body>
<div>
    <?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    <svg xmlns="http://www.w3.org/2000/svg"
         xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
             width="1200" height="1024"
             viewBox="0 0 1200 1024" >

      <defs>

          <g id="colormap"></g>

          <!-- Filter Definition -->


         <filter id="linearred">
          <feComponentTransfer>
            <feFuncR type="linear" slope="128" intercept="0"/>
          </feComponentTransfer>
         </filter>


      </defs>
        <g>
            <use id="source" xlink:href="#colormap"/>
            <use y="200"  id= "redoption2" xlink:href="#colormap" filter="url(#linearred)" />
        </g>

    </svg>
</div>
<script>

        var svgns = "http://www.w3.org/2000/svg";
        var svg = document.getElementById("colormap");
        var cellSize = 10;
        var colCount = 16

                for (let r = 0; r < 256; r++) {
                    var cell = document.createElementNS(svgns, "rect");
                    var x = (r % colCount)
                    var y = Math.trunc(r/colCount)
                    cell.setAttributeNS(null, "x", x * cellSize);
                    cell.setAttributeNS(null, "y", y * cellSize);
                    cell.setAttributeNS(null, "width", cellSize);
                    cell.setAttributeNS(null, "height", cellSize);

                    RcolorHex = r.toString(16).padStart(2,"0");

                    hexColor = "#" + RcolorHex + "0000";
                    console.log(x, y, r, RcolorHex);
                    cell.setAttributeNS(null, "fill", hexColor);
                    svg.appendChild(cell);
                }

</script>
</body>
</html>

Upvotes: 1

Views: 189

Answers (1)

Paul LeBeau
Paul LeBeau

Reputation: 101830

Your problem is due to the fact that filters use a different color space for their operations. They use LinearRGB, whereas other colour operations, such as blending to screen, use sRGB.

The solution is to set filters to use sRGB instead.

color-interpolation-filters="sRGB"

<div>
    <?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
    "http://www.w3.org/Graphics/SVG/1.2/DTD/svg11.dtd">
    <svg xmlns="http://www.w3.org/2000/svg"
         xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
             width="1200" height="1024"
             viewBox="0 0 1200 1024" >

      <defs>

          <g id="colormap"></g>
          
          <!-- Filter Definition -->

         
         <filter id="linearred" color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="linear" slope="128" intercept="0"/>
          </feComponentTransfer>
         </filter>
          
          
      </defs>
        <g>
            <use id="source" xlink:href="#colormap"/>
            <use y="200"  id= "redoption2" xlink:href="#colormap" filter="url(#linearred)" />
        </g>

    </svg>
</div>
<script>

        var svgns = "http://www.w3.org/2000/svg";
        var svg = document.getElementById("colormap");
        var cellSize = 10;
        var colCount = 16

                for (let r = 0; r < 256; r++) {
                    var cell = document.createElementNS(svgns, "rect");
                    var x = (r % colCount)
                    var y = Math.trunc(r/colCount)
                    cell.setAttributeNS(null, "x", x * cellSize);
                    cell.setAttributeNS(null, "y", y * cellSize);
                    cell.setAttributeNS(null, "width", cellSize);
                    cell.setAttributeNS(null, "height", cellSize);

                    RcolorHex = r.toString(16).padStart(2,"0");

                    hexColor = "#" + RcolorHex + "0000";
                    //console.log(x, y, r, RcolorHex);
                    cell.setAttributeNS(null, "fill", hexColor);
                    svg.appendChild(cell);
                }

</script>

It's actually IE/Edge that is wrong here, not Chrome and Firefox :)

Upvotes: 2

Related Questions