Fabric.js - 色彩滤镜

4

我似乎无法让fabric.js的色调过滤器功能正常工作,也找不到任何使用它的实例。我已经尝试了以下方法:

img.filters[0] = new f.Tint({
    color:'green'
});

我也尝试过用#00ff00代替green,但两者都只会把图片变成黑色。

我有一些PNG图像,它们只有黑色和透明度(例如基本形状),我想要能够改变它们的颜色,我不知道这是否可能,但我觉得“着色”听起来很有前途,只是我无法使其工作。

我也在照片上尝试使用它,结果仍然变成黑色,我在代码中同样的位置使用其他滤镜(如反转),它就可以正常工作。

任何帮助都将不胜感激。

更新: 完整的JS代码已被使用,然而第三张图片仅呈现为黑盒子。

var canvas = new fabric.Canvas('c');
var f = fabric.Image.filters;

fabric.Image.fromURL('img/picture3.jpg', function(img) {
  img.set({
    left: 100,
    top: 120,
    angle: 0
  });
  img.filters[0] = new f.Tint({
      color:'00FF00'
  });
  img.applyFilters(canvas.renderAll.bind(canvas));
  canvas.add(img);
});
5个回答

4

我写了这个过滤器,并在我们的一个项目中广泛使用,到目前为止它工作得很好。但是我缺少调用applyFilters的代码-也许你可以发布更多的代码?

另外,我认为我总是像这样应用颜色:

img.filters[0] = new f.Tint({
    color:'FF0000'
});

意思是没有颜色名称,也没有前缀哈希。我知道颜色解析器应该更加健壮。还要确保此过滤器仅适用于具有Alpha通道的图像-即半透明png文件。


感谢您的回复,我已经更新了问题并提供了完整的JS代码。即使没有哈希或颜色名称,图像仍然只是一个黑色框。 - Ben
你手头的是jpg格式的图片,而jpg格式不支持alpha通道。你需要使用半透明的png格式图片,否则就必须重新设计滤镜,将某种颜色作为背景,比如白色。 - Alexander Kludt
嗯...我已经尝试使用部分透明的PNG格式,但现在似乎没有任何反应!我不太确定它应该做什么,也不认为它会做我想要的事情。不过还是谢谢你的帮助。 - Ben

3
我分析了色调滤镜的原始类,发现这一行:
var rgb = parseInt(this.color, 10).toString(16);

应该像这样进行调整。
var rgb = this.color;

为了让它按预期工作。当然,这时rgb变量是无用的,你可以直接将其更改为this.color,但我个人更喜欢单行更改。
我不确定将十六进制转换为整数,再转换为字符串的原始目的是什么,因为这对我来说毫无意义。
您可能不想修改fabric.js源代码,因此建议您根据Filters部分中提到的本教程创建自定义过滤器类:http://fabricjs.com/fabric-intro-part-2/

1
我曾经遇到过同样的问题,无论是JPEG图像还是带有透明背景的PNG图像。
我发现Tint类在这方面没有正常工作,所以我稍微改变了它。您可以在Google Groups上找到相关帖子:https://groups.google.com/forum/#!msg/fabricjs/DPN0WuRtc-o/ZGgIQK5F9xAJ 这是我的解决方法类(通过使用完整的十六进制值来工作,但您可以轻松地根据自己的需求进行调整):
  fabric.Image.filters.Tint = fabric.util.createClass({

  type: 'Tint',

  /**
   * Constructor
   * @memberOf fabric.Image.filters.Tint.prototype
   * @param {Object} [options] Options object
   */
  //That's Different : HexColor
  initialize: function(HexColor) {
    this.color = HexColor;
  },


  /**
   * Applies filter to canvas element
   * @param {Object} canvasEl Canvas element to apply filter to
   */
  applyTo: function(canvasEl) {
    var context = canvasEl.getContext('2d'),
        imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
        data = imageData.data;

    //That's different : computation of values
    var rUser = ((this.color).toString ()).substr(0,2);
    var gUser = ((this.color).toString ()).substr(2,2);
    var bUser = ((this.color).toString ()).substr(4,2);


    for (var i = 0, len = data.length; i < len; i += 4) {


        r = data[i];
        g = data[i + 1];
        b = data[i + 2];

        data[i] = parseInt ((r * parseInt (rUser, 16))/255);
        data[i + 1] = parseInt ((g * parseInt (gUser, 16))/255);
        data[i + 2] = parseInt ((b * parseInt (bUser, 16))/255);


    }

    context.putImageData(imageData, 0, 0);
  },

/**
 * Returns json representation of filter
 * @return {Object} json representation of filter
 */
toJSON: function() {
  return {
    type: this.type,
    color: this.color
  };
}

})`

我用它的方式如下:

//$oCanvas is my fabric Canvas object
//data.color could be 'ff0000' but not 'f00' not anything else like fabric.Color
$img.filters[0] = new fabric.Image.filters.Tint(data.color); 
$img.applyFilters($oCanvas.renderAll.bind($oCanvas));

希望对某些人有所帮助。
L.
编辑
在Tint Filter类中进行了一些更改(Github:https://github.com/kangax/fabric.js/pull/862)。
我再次测试,但仍没有运气,所以我稍微再次更改了它。您可以在Google Groups上找到源代码+说明(https://groups.google.com/forum/#!topic/fabricjs/DPN0WuRtc-o
第二次编辑
好的,Kienz制作了一个JSFiddle(http://jsfiddle.net/Kienz/4wGzk/),其中使用了Tint Filter类和bugfix,并使其正常工作。我建议按照他的方式实施它。

0

我也遇到了同样的问题。最后发现是我使用的fabric js版本问题。为了避免影响其他功能,我没有更新到最新版本,只获取了需要的内容,并将其用作自定义过滤器来覆盖当前的色调实现。

这是我使用的代码:

/**
   * Tint filter class
   * Adapted from <a href="https://github.com/mezzoblue/PaintbrushJS">https://github.com/mezzoblue/PaintbrushJS</a>
   * @class fabric.Image.filters.Tint
   * @memberOf fabric.Image.filters
   * @extends fabric.Image.filters.BaseFilter
   * @see {@link fabric.Image.filters.Tint#initialize} for constructor definition
   * @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}
   * @example <caption>Tint filter with hex color and opacity</caption>
   * var filter = new fabric.Image.filters.Tint({
   *   color: '#3513B0',
   *   opacity: 0.5
   * });
   * object.filters.push(filter);
   * object.applyFilters(canvas.renderAll.bind(canvas));
   * @example <caption>Tint filter with rgba color</caption>
   * var filter = new fabric.Image.filters.Tint({
   *   color: 'rgba(53, 21, 176, 0.5)'
   * });
   * object.filters.push(filter);
   * object.applyFilters(canvas.renderAll.bind(canvas));
   */
  fabric.Image.filters.Tint = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Tint.prototype */ {

    /**
     * Filter type
     * @param {String} type
     * @default
     */
    type: 'Tint',

    /**
     * Constructor
     * @memberOf fabric.Image.filters.Tint.prototype
     * @param {Object} [options] Options object
     * @param {String} [options.color=#000000] Color to tint the image with
     * @param {Number} [options.opacity] Opacity value that controls the tint effect's transparency (0..1)
     */
    initialize: function(options) {
      options = options || { };

      this.color = options.color || '#000000';
      this.opacity = typeof options.opacity !== 'undefined'
                      ? options.opacity
                      : new fabric.Color(this.color).getAlpha();

      console.log(this.color + " " + this.opacity);                
    },

    /**
     * Applies filter to canvas element
     * @param {Object} canvasEl Canvas element to apply filter to
     */
    applyTo: function(canvasEl) {
      var context = canvasEl.getContext('2d'),
          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
          data = imageData.data,
          iLen = data.length, i,
          tintR, tintG, tintB,
          r, g, b, alpha1,
          source;

      source = new fabric.Color(this.color).getSource();

      tintR = source[0] * this.opacity;
      tintG = source[1] * this.opacity;
      tintB = source[2] * this.opacity;

      alpha1 = 1 - this.opacity;

      for (i = 0; i < iLen; i+=4) {
        r = data[i];
        g = data[i + 1];
        b = data[i + 2];

        // alpha compositing
        data[i] = tintR + r * alpha1;
        data[i + 1] = tintG + g * alpha1;
        data[i + 2] = tintB + b * alpha1;
      }

      context.putImageData(imageData, 0, 0);
    },

    /**
     * Returns object representation of an instance
     * @return {Object} Object representation of an instance
     */
    toObject: function() {
      return extend(this.callSuper('toObject'), {
        color: this.color,
        opacity: this.opacity
      });
    }
  });

0
我在做类似的事情时注意到一件事,就是直到图像本身被添加到画布上,过滤器才会起作用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接