在HTML5 Canvas上擦除图像的部分?

时间:2015-02-10 17:29:52

标签: javascript html5 kineticjs konvajs

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

enter image description here

如何在HTML5画布上删除部分图像?

3 个答案:

答案 0 :(得分:3)

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

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

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

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

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

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

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

  • drawImage将您的图片放到画布上,

  • 创建Kinetic.Image并将其image属性设置为对本机画布的引用。 Kinetic.Image将显示绘制到原生画布上的任何内容。

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

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

你的Kinetic.Image正好反映了它的画布来源(var c),所以你的Kinetic.Image也会显示正在被动画圈圈消失运动所删除的图像。

选项#2:使用Kinetic.Shape

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

var ctx = myShapeLayer.getContext()._context;

这是一个较弱的选择,因为KineticJS将重绘形状 - 导致您的删除被撤消。因此,您必须执行额外步骤,以保存所有圆圈橡皮擦的移动并重放这些移动(在drawFunc中)以重做您的擦除。

答案 1 :(得分: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();
    });
}

答案 2 :(得分: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,但我不确定你是如何用圆圈做的。