如何检查画布上是否绘制了某些内容

28

如何检查画布上是否有数据或图像?

我有这个<canvas id="my-canvas"></canvas>元素,并且我想检查我的画布上是否有东西被绘制。


你的画布在哪里?在页面上?在小程序上?还是在移动端? - Harry Joy
我编辑了我的帖子。基本上我只是想检查一下我的 HTML 页面上的元素是否有绘制出来。 - Marvzz
画布中是否有本地绘图功能需要监控?人们如何在画布上绘制? - Caspar Kleijne
8个回答

33

我发现一个好方法是使用toDataURL()函数并将其与另一个空画布进行比较。如果它们不同,那么你正在比较的这个画布上有东西。像这样:

canvas = document.getElementById('editor');
ctx = canvas.getContext('2d');

canvas.addEventListener('mousemove',function(e){
    ctx.lineTo(e.pageX,e.pageY);
    ctx.stroke();
});

document.getElementById('save').addEventListener('click',function(){
    if(canvas.toDataURL() == document.getElementById('blank').toDataURL())
        alert('It is blank');
    else
        alert('Save it!');
});

这里有一个示例

我不能为此负责,我只是偶然发现它,并且解决了我相同的问题。也许这会在某个时候帮助到某人。


当我获取空画布的.toDataURL()时,它也会返回数据URL,因此我无法像您那样进行比较。 - Akshay Chawla

16

不是检查每个像素,仅记录画布何时被填充或描边可能更高效。

一旦发生填充或描边,您就知道有东西被绘制了。

当然,“如何”非常应用程序特定,因为我们不知道您的画布首先是如何被绘制的。


9

我在Stackoverflow上还没有看到这种问题..但是回答起来很有趣..

唯一的方法(我猜)就是逐像素检查,即检查每个像素的R, G, B, A值,
如果这些值都等于零,那么我们可以说这个像素是空的..
这就是我用来编写下面代码片段的技巧..只需浏览以下代码

window.onload = function() {
  var canvas  = document.getElementById('canvas');
  if(!canvas.getContext) return;
  var ctx     = canvas.getContext('2d');
  var w       = canvas.width = canvas.height = 100;
  var drawn   = null;
  var d       = ctx.getImageData(0, 0, w, w); //image data 
  var len     = d.data.length;
  for(var i =0; i< len; i++) {
    if(!d.data[i]) {
      drawn = false;
    }else if(d.data[i]) {
      drawn = true;
      alert('Something drawn on Canvas');
      break;
    }
  }
  if(!drawn) {
    alert('Nothing drawn on canvas.. AKA, Canvas is Empty');
  }
}

Test it Here


谢谢,这看起来很合理,但似乎不太实用(代码可能适用于某些情况)。我确实尝试了这段代码,但它会显著减慢页面速度。经常会在Firefox中收到“停止脚本”消息。也许问题在于我的画布相当大(575px x 500px)? - Marvzz
我在 (1280 X 580) http://jsbin.com/ofoto4/5 进行测试时没有发现任何问题。在 Firefox 3.6.13 上进行了测试。 - user372551
我可能会在代码的其他部分遇到一些问题。无论如何,感谢您的帮助。我仍会考虑这个建议并记下来。 :) - Marvzz
2
  1. 设置drawn=false,如果遇到!0,则设置为true
  2. 从图像中分离数据:var imgData = d.data,但更好的方法是:
  3. 樱桃:使用Int32Array一次测试4个组件: var arr32 = new Int32Array(d.data.buffer); len = arr32.length;你将会快4倍以上。(while ((i<len)&&!arr32[i++]){}; drawn=(i!=len);是此代码的紧凑形式:-))
- GameAlchemist

2

HTML代码:

<canvas id='mainCanvas' style='border:solid'></canvas>
<canvas id='blankCanvas' style='display:none'></canvas>

JS 代码:

var mainCanvas= new SignaturePad(document.getElementById("mainCanvas"));
if (mainCanvas.toDataURL() == document.getElementById('blankCanvas').toDataURL()) {
                // Canvas is blank
}

注意:如果您为主画布提供高度和宽度,则空白画布也会应用相同的高度和宽度。

这节省了我很多时间。原来,在PC和移动浏览器中,.toDataURL()函数返回的空画布不同。例如,我在PC上比较了一个硬编码的“data:image/…”空画布blob和实际画布的.toDataURL(),但是在手机上它不能像在PC上那样正确地工作。创建一个隐藏的画布并将其与正在显示的画布进行比较解决了问题。谢谢! - Nandostyle

2

嘿,可能有点晚回答,但我感到需要额外的画布来进行比较,这让我感到有些恐慌。所以这是我的解决方案:

if (canvas.toJSON().objects.length === 0) {
    console.log('canvas is empty');
}

我希望这能帮到你,你可以用它来创建一个函数,但解决方案比我之前见过的更加干净。


canvas.toJSON() 函数不存在。 - pref

1
要获取画布的像素,您需要使用getImageData()方法 -> getImageData() reference
要检查imageData的每个像素是否为0或255。
您的ImageData每个像素将有4个单元格,r g b a,您可以通过将计数器增加4并查看每4个相邻数字来访问每个像素以获取rgba值。
您还可以获取空图像的DataURL并将其与画布的DataURL进行比较以查看它是否为空 ;)

1

这里有一个来自Phrogz的提示:https://dev59.com/z2445IYBdhLWcg3w5OEH#4649358

function eventOnDraw( ctx, eventName ){
  var fireEvent = function(){
    var evt = document.createEvent("Events");
    evt.initEvent(eventName, true, true);
    ctx.canvas.dispatchEvent( evt );
  }
  var stroke = ctx.stroke;
  ctx.stroke = function(){
    stroke.call(this);
    fireEvent();
  };
  var fillRect = ctx.fillRect;
  ctx.fillRect = function(x,y,w,h){
    fillRect.call(this,x,y,w,h);
    fireEvent();
  };
  var fill = ctx.fill;
  ctx.fill = function(){
    fill.call(this);
    fireEvent();
  };
}
...
var myContext = someCanvasElement.getContext('2d');
someCanvasElement.addEventListener( 'blargle', myHandler, false );
eventOnDraw( myContext, 'blargle' );

1
我知道这可能是一个晚回答,但请尝试此解决方案:
Simon Sarris说过: “与其检查每个像素,记录画布何时被填充或描边可能更有效。”
虽然这样会更有效率,但我找到了一种方法来检测画布是否被绘制/涂鸦,即检查每个像素。我试着玩了一下,看看当画布为空时像素数据返回什么结果,以及在涂鸦时返回什么结果。我发现当画布为空时,数组的所有索引位置上的像素数据都返回0。因此,我使用这个来检测是否有任何0,作为结果,我使它返回一个布尔值。如果画布已经被涂鸦,则返回true,否则返回false。
您可以在JSFiddle上这里测试它。
代码:
function isDrawnOn() {
            var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
            var data = imageData.data;
            var result = null;
            var counter = 0;
            var last = data.length - 1;
            for (var i = 0; i < data.length; i++) {
                if (i === last && counter !== 0 && counter === last) {
                    result = false;
                    break;
                } else if (data[i] !== 0 && data[i] > 0) {
                    result = true;
                    break;
                } else {
                    counter++;
                    continue;
                }
            }
            return result;
        }

我希望这有所帮助 :)


如果相同颜色的数据被绘制在相同颜色的背景上,会怎样呢? - Mister SirCode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接