Fabric.JS 和 Fabric-Brush - 无法添加到较低的 canvas

Fabric.JS and Fabric-Brush - Can't add to lower canvas

我正在尝试使用 Fabric.js with Fabric Brush 我 运行 遇到的这个问题是 Fabric Brush 只将笔触放在顶部 Canvas 而不是底部 canvas。 (fabric.js 中的库存画笔保存到底部 canvas)我想我需要将 "this.canvas.contextTop.canvas" 转换为一个对象并将该对象添加到较低的 canvas。有什么想法吗?

我试过了运行:

this.canvas.add(this.canvas.contextTop)

  onMouseUp: function (pointer) {this.canvas.add(this.canvas.contextTop)}

但我收到错误

Uncaught TypeError: obj._set is not a function

因此 contextTop 是 CanvasHTMLElement 上下文。你不能添加它。 您可以添加到 fabricJS canvas 只是 fabric.Object 派生的 类.

目前看来是不可能的。 它们以像素效果绘制,然后允许您导出为图像。 扩展 fabricJS 画笔接口以创建可重绘对象会很好。

截至目前,使用 fabricJS 和特定版本的织物刷,您唯一可以做的是:

var canvas = new fabric.Canvas(document.getElementById('c'))

canvas.freeDrawingBrush = new fabric.CrayonBrush(canvas, {
  width: 70,
  opacity: 0.6,
  color: "#ff0000"
});

canvas.isDrawingMode = true

canvas.on('mouse:up', function(opt) {
  if (canvas.isDrawingMode) {
    var c = fabric.util.copyCanvasElement(canvas.upperCanvasEl);
    var img = new fabric.Image(c);
    canvas.contextTopDirty = true;
    canvas.add(img);
    canvas.isDrawingMode = false;
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.1/fabric.min.js"></script>
<script src="https://tennisonchan.github.io/fabric-brush/bower_components/fabric-brush/dist/fabric-brush.min.js"></script>
<button>Enter free drawing</button>
<canvas id="c" width="500" height="500" ></canvas>

这只是从 contextTop 创建图像并添加为对象。

我采用了 AndreaBogazzi 建议的方法并修改了 Fabric Brush,以便它在 Fabric Brush 内部进行从上到下的转移 canvas(作为图像)。我还使用了一些我发现的代码,这些代码将图像裁剪为更小的边界框,使其小于 canvas 的完整大小。 Fabric Brush 中的每个画笔都有一个 onMouseUp 函数,代码应放置在该函数中。使用SprayBrush的案例,这里的原始代码是:

onMouseUp: function(pointer) { },

并替换为以下代码:

    onMouseUp: function(pointer){
        function trimbrushandcopytocanvas() {
            let ctx = this.canvas.contextTop;
            let pixels = ctx.getImageData(0, 0, canvas.upperCanvasEl.width, canvas.upperCanvasEl.height),
                l = pixels.data.length,
                bound = {
                    top: null,
                    left: null,
                    right: null,
                    bottom: null
                },
                x, y;
            // Iterate over every pixel to find the highest
            // and where it ends on every axis ()
            for (let i = 0; i < l; i += 4) {
                if (pixels.data[i + 3] !== 0) {
                    x = (i / 4) % canvas.upperCanvasEl.width;
                    y = ~~((i / 4) / canvas.upperCanvasEl.width);

                    if (bound.top === null) {
                        bound.top = y;
                    }

                    if (bound.left === null) {
                        bound.left = x;
                    } else if (x < bound.left) {
                        bound.left = x;
                    }

                    if (bound.right === null) {
                        bound.right = x;
                    } else if (bound.right < x) {
                        bound.right = x;
                    }

                    if (bound.bottom === null) {
                        bound.bottom = y;
                    } else if (bound.bottom < y) {
                        bound.bottom = y;
                    }
                }
            }
            // Calculate the height and width of the content
            var trimHeight = bound.bottom - bound.top,
                trimWidth = bound.right - bound.left,
                trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
            // generate a second canvas
            var renderer = document.createElement('canvas');
            renderer.width = trimWidth;
            renderer.height = trimHeight;
            // render our ImageData on this canvas
            renderer.getContext('2d').putImageData(trimmed, 0, 0);
            var img = new fabric.Image(renderer,{
                scaleY: 1./fabric.devicePixelRatio,
                scaleX: 1./fabric.devicePixelRatio,
                left: bound.left/fabric.devicePixelRatio,
                top:bound.top/fabric.devicePixelRatio
            });
            this.canvas.clearContext(ctx);
            canvas.add(img);
        }
        setTimeout(trimbrushandcopytocanvas, this._interval); // added delay because last spray was on delay and may not have finished
    },

使用setTimeout功能是因为Fabric Brush在mouseup事件发生后仍然可以绘制到上层canvas,并且有时会继续绘制上层canvas 在其上下文被清除后。