2

我有一个 HTML5 画布。我正在使用KineticJS(KonvaJS)画布库。在空白画布上,我绘制了如下图所示的图像。现在我想创建一个圆形,可以用来擦除图像的一部分。图中红色圆圈为橡皮擦。

在此处输入图像描述

如何擦除 HTML5 Canvas 上的部分图像?

4

3 回答 3

3

您可以使用合成来“擦除”像素。

具体来说,您使用destination-out合成。

KineticJS 不支持合成,但您仍然有几个选择:

(注:KineticJS 已经变成了 KonvaJS,我还没有检查 KonvaJs 是否支持合成。如果现在支持,只需destination-out在 KonvaJS 中使用合成)

选项#1:使用原生画布元素作为 Kinetic.Image 源

  • 使用创建内存中的 html5 画布var c=document.createElement

  • 将画布调整为图像大小,

  • drawImage你的图像到画布上,

  • 创建一个Kinetic.Image并将其图像属性设置为对本机画布的引用。Kinetic.Image 将显示在本机画布上绘制的任何内容。

    var kImage=new Kinetic.Image({
    ...
    image:c,
    ...
    
  • 设置画布合成以使新绘图“擦除”现有像素:

    c.globalCompositeOperation='destination-out';
    
  • 监听圆形橡皮擦上的拖动事件。使用这些事件在画布上绘制一个圆圈,该圆圈的移动就像 Kinetic 圆形橡皮擦的移动一样。由于画布的合成设置为“擦除”,画布上新绘制的圆圈将擦除画布上的图像。

您的 Kinetic.Image 准确地反映了它的画布源 (var c),因此您的 Kinetic.Image 还将显示正在擦除的图像以响应 Kinetic 圆形橡皮擦的移动。

选项#2:使用 Kinetic.Shape

您可以通过在单独的图层上创建 Kinetic.Shape 并使用以下方法获取对本机画布上下文的引用来执行与 Option#1 相同的操作:

var ctx = myShapeLayer.getContext()._context;

这是一个较弱的选项,因为 KineticJS 将重新绘制形状——导致您的擦除被撤消。因此,您必须执行额外的步骤,即保存所有圆形橡皮擦的动作并重播这些动作(在 中drawFunc)以重新擦除。

于 2015-02-10T18:24:31.387 回答
3

感谢markE的详细回答,

我试图从中获取上下文Konva.Layer()并且它起作用了。

    var freeHandDrawingImage = new Image();
    freeHandDrawingImage.onload = function() {
        var context = freeHandDrawingLayer.getContext('2d');
        context.drawImage(this, 0,0);
        context.globalCompositeOperation='destination-out';
        freeHandDrawingLayer.draw();
    };
    freeHandDrawingImage.src = "image.png";

我已经使用自定义Konva.Shape擦除"destination-out"和绘制自由绘制"source-over"

freeDrawingType = 'brush';
isFreeDrawingMode = false;
isPaint = false;
lastPointerPosition = {};

drawFreeDrawings = function(){

    var freeDraw = new Konva.Shape({
        name: "freeDraw",
        stroke: 'black',
        strokeWidth: 5,
        closed : false,
        sceneFunc: function(context){
            // free draw quad
            debugger;
            if(isPaint){
                if (freeDrawingType === 'brush') {
                    context.globalCompositeOperation = 'source-over';
                }
                if (freeDrawingType === 'eraser') {
                    context.globalCompositeOperation = 'destination-out';
                }
                context.beginPath();
                context.moveTo(lastPointerPosition.x, lastPointerPosition.y);
                var newPosition = stage.getPointerPosition();

                context.lineTo(newPosition.x, newPosition.y);
                context.stroke();
                debugger;
                lastPointerPosition = newPosition;
                context.strokeShape(this);

            }
        }
    });
    freeHandDrawingLayer.add(freeDraw);
    // now we need to bind some events
    // we need to start drawing on mousedown
    // and stop drawing on mouseup
    selectionBoxBackground.on('mousedown', function() {
        if(isFreeDrawingMode){
            isPaint = true;
            lastPointerPosition = stage.getPointerPosition();
            stage.draw();
        }
    });

    selectionBoxBackground.on('mouseup', function() {
        if(isFreeDrawingMode){
            isPaint = false;
        }
    });

    // and core function - drawing
    selectionBoxBackground.on('mousemove', function() {
            if (!isPaint) {
                return;
            }      
            freeHandDrawingLayer.draw();
    });
}
于 2016-04-18T12:50:41.107 回答
0

在纯 JavaScript 中,这非常简单。

首先准备好你的画布和绘图上下文:

var context=document.getElementById("your_canvas_id").getContext("2d");
var image=document.getElementById("your_image_id");

现在您想将图像绘制到上下文中:

context.drawImage(image,0,0,image.width,image.height,0,0,image.width,image.height);

现在,当您想擦除部分图像时,只需在画布上绘制:

var x=y=radius=10;// Circle coordinates and radius.

context.fillStyle="#ffffff";// Your eraser color (not transparent)
context.beginPath();
context.arc(x,y,radius,0,Math.PI*2);
context.fill();

但是,这仅模拟擦除。如果您希望之后擦除的内容透明,您可能会查看context.clearRect,但我不确定您将如何使用圆圈来做到这一点。

于 2015-02-10T18:08:20.957 回答