【问题标题】:SVG feComposite filter implementation in canvasSVG feComposite 过滤器在画布中的实现
【发布时间】:2017-08-02 00:04:17
【问题描述】:

我正在画布中实现 SVG 过滤器,但复合算术运算符有两个问题。

我对这个运算符的实现是基于W3C specification 和 firefox9 源代码。

这是我的过滤器和 svg 示例代码:Fiddle complete code

var k1Scaled = options.k1 / 255;
var k4Scaled = options.k4 * 255;
for(v=0; v<datas.length; v+=4) {
   r = datasB1[v+0];
   g = datasB1[v+1];
   b = datasB1[v+2];
   a = datasB1[v+3];
   r1 = datasB2[v+0];
   g1 = datasB2[v+1];
   b1 = datasB2[v+2];
   a1 = datasB2[v+3];
   //if (a === 0 && a1 === 0) continue;
   vR = k1Scaled * r1 * r + options.k2 * r + options.k3 * r1 + k4Scaled;
   vG = k1Scaled * g1 * g + options.k2 * g + options.k3 * g1 + k4Scaled;
   vB = k1Scaled * b1 * b + options.k2 * b + options.k3 * b1 + k4Scaled;
   vA = k1Scaled * a1 * a + options.k2 * a + options.k3 * a1 + k4Scaled;
   datas[v+0] = Math.min(Math.max(0, ~~vR), 255);
   datas[v+1] = Math.min(Math.max(0, ~~vG), 255);
   datas[v+2] = Math.min(Math.max(0, ~~vB), 255);
   datas[v+3] = Math.min(Math.max(0, ~~vA), 255);
}

我的第一个问题:由于公式,我在透明像素上有银色,如果我在透明像素上分解公式,结果是:

结果 = k1*i1*i2 + k2*i1 + k3*i2 + k4

其中 k1 = 0.5 / 255 = 0.0019,i1 = 0,i2 =0,k2 = 0.5,k3 = 0.5,k4 = 0.5 * 255 = 127

结果 = 0.0019*0*0 + 0.5*0 + 0.5*0 + 127 = 127 => rgba 上的银

我的第二个问题:我的结果比 svg 示例更不透明,我想 webbrowser 预乘了 rgba 结果,但我尝试了这个但没有结果。

我不能在画布上使用 svg 过滤器,我需要纯 javascript/canvas 实现。

如果您有任何想法或解决方案,请提前致谢。

克兰。

【问题讨论】:

  • 为什么不能在画布上使用 svg 过滤器?您知道您可以将您的context's filter 设置为指向文档ctx.filter = 'url(#yourSvgFilter)' 中的一个svg
  • 感谢 Michael,Kaiido,只有 chrome 可以在 canvas、firefox 和 ie 崩溃上正确应用多个 svg 过滤器,这就是我在纯 javascript 中实现的原因
  • 如果 FF 崩溃,请在 bugzilla 上打开错误报告。
  • @kran 抱歉,我很抱歉添加了不需要的 porterDuff “over”。但这并不能摆脱黑色。我会说它是画布,它使所有透明像素变黑,您的图像在 RGB 中有透明像素的颜色。但是在进一步的测试和作弊(使用文件侧步进画布中的原始像素数据)中,我的答案对于 k1、k2、k3、k4 的某些值来说是遥不可及的,所以我会收回它。抱歉,我帮不上忙。
  • Ps:对我来说它根本不会崩溃jsfiddle.net/Kaiido/cv1bLcmn/20

标签: javascript html canvas svg svg-filters


【解决方案1】:

Here the solution

this._arithmetic = function(options, ctx) {
  var b1, ctxB1, ctxB2, w, h, x, y, v, imgDatas, datas, imgDatasB1, datasB1, imgDatasB2, datasB2;
  b1 = document.createElement("canvas");
  ctxB1 = b1.getContext("2d");
  ctxB1.resize(this.width,this.height);
  ctxB1.drawImage(options.in.source, options.in.options.x, options.in.options.y, options.in.options.width, options.in.options.height);
  imgDatasB1 = ctxB1.getImageData(0,0,this.width,this.height);
  this.premultiply(imgDatasB1);
  datasB1 = imgDatasB1.data;

  b2 = document.createElement("canvas");
  ctxB2 = b2.getContext("2d");
  ctxB2.resize(this.width,this.height);
  ctxB2.drawImage(options.in2.source, options.in2.options.x, options.in2.options.y, options.in2.options.width, options.in2.options.height);
  ctx.resize(this.width,this.height);
  ctx.drawImage(b2, 0, 0);
  imgDatas = ctx.getImageData(0,0,this.width,this.height);
  this.premultiply(imgDatas);
  datas = imgDatas.data;
  var k1Scaled = options.k1 / 255;
  var k4Scaled = options.k4 * 255;
  var vR,vG,vB,vA,r,g,b,a,r1,g1,b1,a1;
  for(v = 0;v < datas.length;v += 4) {
    r = datasB1[v + 0];
    g = datasB1[v + 1];
    b = datasB1[v + 2];
    a = datasB1[v + 3];

    r1 = datas[v + 0];
    g1 = datas[v + 1];
    b1 = datas[v + 2];
    a1 = datas[v + 3];

    vR = k1Scaled * r1 * r + options.k2 * r + options.k3 * r1 + k4Scaled;
    vG = k1Scaled * g1 * g + options.k2 * g + options.k3 * g1 + k4Scaled;
    vB = k1Scaled * b1 * b + options.k2 * b + options.k3 * b1 + k4Scaled;
    vA = k1Scaled * a1 * a + options.k2 * a + options.k3 * a1 + k4Scaled;

    vR = vR < 0 ? 0 : vR > 255 ? 255 : vR;
    vG = vG < 0 ? 0 : vG > 255 ? 255 : vG;
    vB = vB < 0 ? 0 : vB > 255 ? 255 : vB;
    vA = vA < 0 ? 0 : vA > 255 ? 255 : vA;

    datas[v + 0] = vR;
    datas[v + 1] = vG;
    datas[v + 2] = vB;
    datas[v + 3] = vA;
  }
  this.unPremultiply(imgDatas);
  ctx.putImageData(imgDatas,0,0);
};

premultiply/unPremultiply 函数的代码在小提琴链接中。

【讨论】:

    猜你喜欢
    • 2020-01-03
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 2012-06-01
    • 2020-07-09
    • 2021-03-15
    • 2014-11-22
    • 1970-01-01
    相关资源
    最近更新 更多