如何用 Easeljs/Createjs 中的颜色覆盖 Bitmap 的非透明部分?

How to overlay non-transparent part of Bitmap with a color in Easeljs/Createjs?

我有一张 PNG 图像,其中有一些透明部分。现在我想在图像的非透明部分应用颜色叠加,同时保持透明部分不变。

如果我使用 ColorFilter 它会填满整个位图。我也尝试过 AlphaMaskFilter(使用与源相同的 PNG),但它也不起作用。整个位图总是充满颜色。

关于如何操作还有其他建议吗?

您必须编写一个过滤器:

  • 像 AlphaMaskFilter 一样工作,只使用 rect()source-out 复合操作 OR
  • 与 AlphaMapFilter 类似,但在源图像中遇到空像素的地方绘制一个彩色像素。

这是一个使用上述第一种方法的示例插件,这可能是最有效的:

(function () {
    "use strict";
    function ColorMaskFilter(color) {
        this.color = color;
    }
    var p = createjs.extend(ColorMaskFilter, createjs.Filter);
    p.applyFilter = function (ctx, x, y, width, height, targetCtx, targetX, targetY) {
        if (!this.color) { return true; }
        targetCtx = targetCtx || ctx;
        if (targetX == null) { targetX = x; }
        if (targetY == null) { targetY = y; }

        targetCtx.save();
        if (ctx != targetCtx) {
            return false;
        }

        targetCtx.globalCompositeOperation = "source-out"; // Use source-in to fill the shape instead
    targetCtx.fillStyle = this.color;
        targetCtx.rect(targetX,targetY,width,height);
    targetCtx.fill();

        targetCtx.restore();
        return true;
    };
    p.clone = function () {
        return new AlphaMaskFilter(this.color);
    }; 
    createjs.ColorMaskFilter = createjs.promote(ColorMaskFilter, "Filter");
}());

我用这个例子快速 fiddle 组合了一个:http://jsfiddle.net/dbtwd463/

注:根据原文编辑,仅建议包含样本的方法和 fiddle

根据 Lanny 的建议,我想出了这个过滤器。

<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>

<canvas id="canvas" width="50" height="50" style="border:1px solid red; background: pink">
        no canvas!
    </canvas>

<script>
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext("2d");
  var stage = new createjs.Stage(canvas);

  function init(img) {
    var bmp = new createjs.Bitmap(img);
    stage.addChild(bmp);
    
    bmp.filters = [new createjs.ColorMaskFilter('#ffff00')];
    bmp.cache(0, 0, 30, 30);

    stage.update();
  }

  (function() {
    "use strict";

    function ColorMaskFilter(color) {
      this.color = color;
    }

    var p = createjs.extend(ColorMaskFilter, createjs.Filter);

    p.applyFilter = function(ctx, x, y, width, height, targetCtx, targetX, targetY) {
      targetCtx = targetCtx || ctx;
      if (targetX == null) {
        targetX = x;
      }
      if (targetY == null) {
        targetY = y;
      }

      targetCtx.save();
      if (ctx != targetCtx) {
        // TODO: support targetCtx and targetX/Y
        // clearRect, then draw the ctx in?
        return false;
      }

      if (!this.mask || this.mask.width != width || this.mask.height != height) {
        var shape = new createjs.Shape();
        shape.graphics.beginFill(this.color || '#ff0000');
        shape.graphics.drawRect(0, 0, width, height);
        shape.cache(0, 0, width, height);

        this.mask = shape.cacheCanvas;
      }

      targetCtx.globalCompositeOperation = "source-in";
      targetCtx.drawImage(this.mask, targetX, targetY);
      targetCtx.restore();
      return true;
    };

    /** docced in super class **/
    p.clone = function() {
      return new ColorMaskFilter(this.color);
    };

    /** docced in super class **/
    p.toString = function() {
      return "[ColorMaskFilter]";
    };


    createjs.ColorMaskFilter = createjs.promote(ColorMaskFilter, "Filter");
  }());
</script>

<hr>Source: <img width="30" height="30" onload="init(this)" title="" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzA5OUIxQjFGQUM5MTFFNjlCRDRBMjM4Qzg2RDM5M0EiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzA5OUIxQjJGQUM5MTFFNjlCRDRBMjM4Qzg2RDM5M0EiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MDk5QjFBRkZBQzkxMUU2OUJENEEyMzhDODZEMzkzQSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MDk5QjFCMEZBQzkxMUU2OUJENEEyMzhDODZEMzkzQSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pkob9IwAAAB0SURBVHjaYmT4X/GfYQAAE8MAARYY4z9DOyM9LGRkqPw/oD4e+KCGgcN2S+WA1ENqW2R7KJpxUPh48AQ1vuAhBwCj7v+g8vGoxaMWj1o8avGoxdSpJHAV8KNBTZWgBtbBj8CNwdFUTfX29UjrwgyYxQABBgBraRUTSfHtgAAAAABJRU5ErkJggg=="
/>