重新填充画布擦除区域的区域

Posted

技术标签:

【中文标题】重新填充画布擦除区域的区域【英文标题】:Re-fill area of erased area for canvas 【发布时间】:2015-12-27 22:50:25 【问题描述】:

我正在尝试使用下面的代码 sn-p 在图像中填充颜色以在画布的图像上填充颜色。它成功地在画布中填充颜色。现在,我正在尝试使用此代码 sn-p 擦除用户触摸时填充的颜色,以擦除画布图像上的颜色。其擦除颜色并在该触摸位置设置透明区域。现在我想在用户触摸时用颜色重新填充该区域,但由于透明像素,它不允许我在该区域上着色。那么有没有办法用颜色重新填充像素或者有没有其他方法可以从画布图像中擦除颜色?任何回复将不胜感激。

用于在画布图像上填充颜色的代码 sn-p

var ctx = canvas.getContext('2d'),
    img = new Image;
img.onload = draw;
img.crossOrigin = 'anonymous';
img.src = "https://dl.dropboxusercontent.com/s/1alt1303g9zpemd/UFBxY.png";

    function draw(color) 
      ctx.drawImage(img, 0, 0);
    
    canvas.onclick = function(e)
       var rect = canvas.getBoundingClientRect();
       var x = e.clientX-rect.left,
           y = e.clientY-rect.top;

        ctx.globalCompositeOperation = 'source-atop';
        ctx.fillStyle = 'blue';
        ctx.beginPath();
        ctx.arc(x-5,y-5,10,0,2*Math.PI);
        ctx.fill();

      

代码 sn-p 用于擦除画布图像上的颜色

(function() 
    // Creates a new canvas element and appends it as a child
    // to the parent element, and returns the reference to
    // the newly created canvas element


    function createCanvas(parent, width, height) 
        var canvas = ;
        canvas.node = document.createElement('canvas');
        canvas.context = canvas.node.getContext('2d');
        canvas.node.width = width || 100;
        canvas.node.height = height || 100;
        parent.appendChild(canvas.node);
        return canvas;
    

    function init(container, width, height, fillColor) 
        var canvas = createCanvas(container, width, height);
        var ctx = canvas.context;
        // define a custom fillCircle method
        ctx.fillCircle = function(x, y, radius, fillColor) 
            this.fillStyle = fillColor;
            this.beginPath();
            this.moveTo(x, y);
            this.arc(x, y, radius, 0, Math.PI * 2, false);
            this.fill();
        ;
        ctx.clearTo = function(fillColor) 
            ctx.fillStyle = fillColor;
            ctx.fillRect(0, 0, width, height);
        ;
        ctx.clearTo(fillColor || "#ddd");

        // bind mouse events
        canvas.node.onmousemove = function(e) 
            if (!canvas.isDrawing) 
               return;
            
            var x = e.pageX - this.offsetLeft;
            var y = e.pageY - this.offsetTop;
            var radius = 10; // or whatever
            var fillColor = '#ff0000';
            ctx.globalCompositeOperation = 'destination-out';
            ctx.fillCircle(x, y, radius, fillColor);
        ;
        canvas.node.onmousedown = function(e) 
            canvas.isDrawing = true;
        ;
        canvas.node.onmouseup = function(e) 
            canvas.isDrawing = false;
        ;
    

    var container = document.getElementById('canvas');
    init(container, 531, 438, '#ddd');

)();

【问题讨论】:

如果要应用填充,请设置globalCompositeOperation='source-over',这将导致在现有图纸上绘制新图纸。 (source-over 是默认的合成模式)。如果要“擦除”,请设置globalCompositeOperation='destination-out',这将导致新绘图清除新像素与现有像素重叠的现有像素。 @markE 我想在图像的非透明区域填充颜色,这就是我使用ctx.globalCompositeOperation = 'source-atop' 填充颜色的原因。要擦除它,我使用了`ctx.globalCompositeOperation = 'destination-out' ` . 查看source-out 合成,它在不与现有像素重叠的地方绘制新像素。在您的情况下,假设用户负责放置新像素的位置可能并不理想,因为新弧可能不会放置在与擦除弧完全相同的位置。也许您最好的解决方案是跟踪用户已擦除的位置,如果他们单击先前已擦除的区域,您可以简单地重新绘制到该已知区域。 @markE 我试图跟踪用户擦除的像素(clearRect(x,y) 的起源)。但是,当我尝试重绘不包括已擦除区域的整个图像时,已擦除区域与未被用户擦除的包围点重叠。所以基本上我必须存储区域(由橡皮擦矩形覆盖)和圆形区域(用户之前填充的颜色)来克服这个问题。我怎样才能实现它? 您对 rects 和 arcs 的使用让我有点困惑,但我已经发布了一个答案,显示如何仅恢复和重新着色擦除矩形内的图像部分供您开始和。您可能需要稍微调整答案,因为我不在我通常用来在发布之前测试我的代码的计算机附近。祝你的项目好运 【参考方案1】:

警告未经测试的代码!

// create a clipping region using your erasing rect's x,y,width,height
context.save();
context.beginPath();
context.rect(erasingRectX,erasingRectY,erasingRectWidth,erasingRectHeight);
context.clip();

// redraw the original image.
// the image will be redrawn only into the erasing rects boundary
context.drawImage(yourImage,0,0);

// compositing: new pixels draw only where overlapping existing pixels
context.globalCompositeOperation='source-in';

// fill with your new color
// only the existing (clipped redrawn image) pixels will be colored
context.fillStyle='red';
context.fillRect(0,0,canvas.width,canvas.height);

// undo the clipping region
context.restore();

【讨论】:

感谢您的关注。它显示红色而不是该图像的一部分。 恐怕我仍然对您需要什么感到困惑,因为我认为您想重新着色未擦除图像的一部分。如果您不需要重新应用颜色,那么您可以跳过 source-in 合成和 fillRect。您将在擦除矩形内重新绘制原始图像。干杯!

以上是关于重新填充画布擦除区域的区域的主要内容,如果未能解决你的问题,请参考以下文章

线下的 HTML 画布填充区域

画布 - 在完全透明的所有区域中填充一个矩形

android 画布区域,android:canvas绘制一个透明矩形并填充其余区域

【UBoot移植】当bootdelay误设置为0时 怎么擦除nandflash里面的程序 重新烧写u-boot没用

谷歌地图:重新定义中心点,适合特定区域的边界

如何缓存静态画布区域以获得性能