【问题标题】:SVG with Filters to HTML5 Canvas Implementation带有过滤器的 SVG 到 HTML5 画布实现
【发布时间】:2016-12-03 05:32:22
【问题描述】:

我正在尝试导出已使用 SVG 过滤器修改以包含投影的图像。由于 CSS 当前不支持阴影传播能力,我为此使用 SVG 过滤器而不是 CSS。不幸的是,canvas 也不支持 Photoshop 之类的阴影扩散功能。画布将写入图像,但不包括 SVG 滤镜,仅包含画布特定的阴影滤镜。

这样做的最终目标是导出包含过滤器的 jpeg 图像。所以它会是 SVG > Canvas > Image。

所以我想我的问题是,如何在绘制图像时欺骗画布以包含 SVG 过滤器?

这是我目前所拥有的。

图像 HTML:

<img ng-src="logo.png" style="-webkit-filter: url("#logo-filter"); filter: url("#logo-filter");" />

SVG 滤镜设置:

    <svg>
      <defs>
        <filter id="logo-filter" x="0" y="0" width="200%" height="200%">
            <feFlood result="flood" flood-color="#00FFFF" flood-opacity="1"></feFlood>
            <feComposite in="flood" result="mask" in2="SourceGraphic" operator="in" />
            <feOffset in="mask" result="offset"  dx="10" dy="10" />
            <feGaussianBlur in="offset" result="blurred" stdDeviation="3" />
            <feComponentTransfer>
                    <feFuncA type="gamma" exponent="0.5" amplitude="3" in="blurred" result="blurred2" />
            </feComponentTransfer>
            <feMerge>
            <feMergeNode in="blurred2"></feMergeNode>
            <feMergeNode in="SourceGraphic"></feMergeNode>
        </feMerge>
        </filter>
    </defs>
</svg>

画布实现:

function plotLogo(img, logo, container) {
      var canvas = document.getElementById("logo-canvas");
      var position = getOffset($('#'+container.id+'-logo'));

      var logo_image = new Image();

      logo_image.src = img;

      logo_image.onload = function(){
        canvas.width = container.width;
        canvas.height = container.height;
        var context = canvas.getContext('2d');

        /* StackOverflow Comment: Works but with no shadow spread */
        context.shadowOffsetX = logo.shadow.offsetX;
        context.shadowOffsetY = logo.shadow.offsetY;
        context.shadowColor = logo.shadow.color;
        context.shadowBlur = logo.shadow.blur*2; //Multiplied by 2 to get closest look to webkit shadow

        context.drawImage(logo_image, position.posX, position.posY, logo.width, logo.height);
      };
    }

【问题讨论】:

    标签: javascript canvas svg html5-canvas


    【解决方案1】:

    我想出了自己问题的答案,这是我想出的解决方案。

    我必须让 SVG 基本上反映用户使用 svg 图像标签操作的内容。两者都链接到过滤器:url(#logo-filter)。

    <svg id="svg-logo" height="175" width="600">
        <defs>
            <filter id="logo-filter" x="-50%" y="-50%" width="200%" height="200%">
                <feFlood result="flood" flood-color="[[params.logo.shadow.color]]" flood-opacity="1"></feFlood>
                <feComposite in="flood" result="mask" in2="SourceGraphic" operator="in" />
                <feOffset in="mask" result="offset"  dx="[[params.logo.shadow.offsetX]]" dy="[[params.logo.shadow.offsetY]]" />
                <feGaussianBlur in="offset" result="blurred" ng-stddeviation="[[params.logo.shadow.blur]]" />
                <feComponentTransfer>
                        <feFuncA type="gamma" exponent="0.5" amplitude="[[params.logo.shadow.spread]]" in="blurred" result="blurred2" />
                </feComponentTransfer>
                <feMerge>
                <feMergeNode in="blurred2"></feMergeNode>
                <feMergeNode in="SourceGraphic"></feMergeNode>
            </feMerge>
            </filter>
        </defs>
        <image id="svg-logo-image" xlink:href="logo.png" filter="url(#[[svg.logo.filter]])" x="0" y="0" />
    </svg>
    

    然后使用 window.btoa 收集 SVG 信息并将其转换为 base64 编码。请注意,除非 xlink:href 也在 base64 图像代码中,否则它将不起作用!

     var svg = document.getElementById('svg-'+type);
     var svgData = new XMLSerializer().serializeToString(svg);
    
     var encodedData = window.btoa(unescape(encodeURIComponent(svgData)));
     var newSrc = 'data:image/svg+xml;base64,'+encodedData;
    

    这是我目前拥有的全部功能。

    function plotImage(element, container, index, img) {
    
      var type = img ? 'logo' : 'address';
      var canvas = document.getElementById(type+'-canvas');
      var svg = document.getElementById('svg-'+type);
      var svgElem = document.getElementById('svg-'+type+'-image');
      var position = getOffset($('#'+container.name+'-'+type), $('#'+container.name));
    
    
      svg.setAttribute('width', container.width);
      svg.setAttribute('height', container.height);
    
      if(typeof img !== 'undefined') {
    
        svgElem.setAttribute('x', position.x);
        svgElem.setAttribute('y', position.y);
        svgElem.setAttribute('width', element.width);
        svgElem.setAttribute('height', element.height);
        svgElem.setAttribute('xlink:href', img);
    
      } else {
    
        svgElem.setAttribute('x', position.x);
        svgElem.setAttribute('y', position.y+(element.size/3)); // Adjust Y via 1/3 of font-size
    
      }
    
      var svgData = new XMLSerializer().serializeToString(svg);
    
      var encodedData = window.btoa(unescape(encodeURIComponent(svgData)));
      var newSrc = 'data:image/svg+xml;base64,'+encodedData;
    
      // Alternate Method, (slower)
      // var svgBlob = new Blob([svgData], {type: "image/svg+xml;charset=utf-8"});
      // var newSrc = window.URL.createObjectURL(svgBlob);
    
      var image = new Image();
      image.src = newSrc;
      image.onload = drawCanvas(image, canvas, container);
    
    }
    

    【讨论】:

      猜你喜欢
      • 2017-08-02
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-24
      • 2013-06-07
      • 2012-05-06
      • 1970-01-01
      • 2017-12-22
      相关资源
      最近更新 更多