无法在 'CanvasRenderingContext2D' 上执行 'createPattern':图像参数是宽度或高度为 0 的 canvas 元素

Failed to execute 'createPattern' on 'CanvasRenderingContext2D': The image argument is a canvas element with a width or height of 0

我正在尝试为 canvas 项目制作放大镜,并且我正在尝试制作一个图案,其中涉及将包含图像副本的 canvas 的一部分复制到第二个,更小,canvas。我让 运行 进入错误状态:

"Failed to execute 'createPattern' on 'CanvasRenderingContext2D': The image argument is 
 a canvas element with a width or height of 0."

代码示例如下:

HTML:

<canvas id="tCanvas" width=240 height=240 style="background-color:aqua;">
</canvas>
<canvas id="canvas1" width=240 height=240 style="background-color:#808080;">
</canvas>
<p></p>
<button id="download"   onclick="magnify();">Zoom</button>

JS:

    var canvas = document.getElementById("canvas1");
    var ctx = canvas.getContext('2d')
    var base64 = canvas.toDataURL('image/png', 0);
    drawing = new Image();
    drawing.src = base64; // can also be a remote URL e.g. http://
    var canvas1 = document.getElementById("tCanvas");
    var ctx1 = canvas1.getContext('2d');
    ctx1.drawImage(drawing, 0, 0);
    let w = drawing.naturalWidth
    let h = drawing.naturalHeight
    let size = w / 4 // Size (radius) of magnifying glass
    let magnification = 2
    let r = size / magnification // Radius of part we want to magnify
    
    let px = w / 3.5
    let py = h / 4

     let tileCanvas = document.getElementById("tCanvas")
     tileCanvas.width = 2 * size
     tileCanvas.height = 2 * size
    
      tileCanvas.getContext('2d').drawImage(canvas, px - r, py - r, 2 * r, 2 * r, 0, 0, 2 * size, 2 * size)
    
      let pattern = ctx.createPattern(tileCanvas, "repeat")
    
      ctx.fillStyle = pattern
   
     ctx.translate(px - size, py - size)

    ctx.beginPath()
    ctx.arc(size, size, size, 0, 2 * Math.PI)
    ctx.fill()
    ctx.strokeStyle = "orangered"
    ctx.lineWidth = 12
    ctx.stroke()
};

这是一个比较经典的问题,由图片加载'asynchronous nature'引起。我们看一下报错信息:

"Failed to execute 'createPattern' on 'CanvasRenderingContext2D': The image argument is a canvas element with a width or height of 0."

它说发送到 createPattern() 方法的对象的高度或宽度为零,但为什么会发生这种情况?

让我们稍微回顾一下您的代码。

有问题的对象是 tileCanvas,它的宽度和高度在这里确定:

 tileCanvas.width = 2 * size
 tileCanvas.height = 2 * size

那么size的价值是多少?再往后退一步就会发现

let size = w / 4

w依次是

let w = drawing.naturalWidth

这是问题的症结所在。 naturalWidth 是图像对象的 属性 - 在您的例子中是 drawing。问题是您在填充 .src 属性 后立即调用它。此时图像可能尚未完全加载,因此它 returns 为零。

您必须等待图像完全加载,才能查询其属性。这是通过监听 onload 事件来完成的。

这是一个例子:

var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext('2d')
var base64 = canvas.toDataURL('image/png', 0);
drawing = new Image();
drawing.onload = () => {
  var canvas1 = document.getElementById("tCanvas");
  var ctx1 = canvas1.getContext('2d');
  ctx1.drawImage(drawing, 0, 0);
  let w = drawing.naturalWidth
  let h = drawing.naturalHeight

  let size = w / 4 // Size (radius) of magnifying glass
  let magnification = 2
  let r = size / magnification // Radius of part we want to magnify

  let px = w / 3.5
  let py = h / 4

  let tileCanvas = document.getElementById("tCanvas")
  tileCanvas.width = 2 * size
  tileCanvas.height = 2 * size

  tileCanvas.getContext('2d').drawImage(canvas, px - r, py - r, 2 * r, 2 * r, 0, 0, 2 * size, 2 * size)

  let pattern = ctx.createPattern(tileCanvas, "repeat")

  ctx.fillStyle = pattern

  ctx.translate(px - size, py - size)

  ctx.beginPath()
  ctx.arc(size, size, size, 0, 2 * Math.PI)
  ctx.fill()
  ctx.strokeStyle = "orangered"
  ctx.lineWidth = 12
  ctx.stroke()
}
drawing.src = base64; // can also be a remote URL e.g. http://
<canvas id="tCanvas" width=240 height=240 style="background-color:aqua;">
</canvas>
<canvas id="canvas1" width=240 height=240 style="background-color:#808080;">
</canvas>
<p></p>
<button id="download" onclick="magnify();">Zoom</button>