Javascript Canvas drawImage在本地运行(但不是从web运行)时抛出索引大小错误

Javascript Canvas drawImage在本地运行(但不是从web运行)时抛出索引大小错误,javascript,html,canvas,Javascript,Html,Canvas,我正在运行MDN教程,使用。精简的页面代码如下所示: <html> <head> <script type="application/x-javascript"> function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.drawImage(document.getElementByI

我正在运行MDN教程,使用。精简的页面代码如下所示:

  <html>
  <head>
    <script type="application/x-javascript">
    function draw() {
           var ctx = document.getElementById('canvas').getContext('2d');
           ctx.drawImage(document.getElementById('frame'),0,0);
           ctx.drawImage(document.getElementById('source'),33,71,104,124,21,20,87,104);
    }
    </script>
  </head>
  <body onload="draw();">
      <canvas id="canvas" width="150" height="150"></canvas>
      <img id="source" src="images/rhino.jpg" width="300" height="227" alt="">
      <img id="frame" src="images/picture_frame.png" width="132" height="150" alt="">
  </body>
</html>

函数绘图(){
var ctx=document.getElementById('canvas').getContext('2d');
ctx.drawImage(document.getElementById('frame'),0,0);
ctx.drawImage(document.getElementById('source'),33,71104124,21,20,87104);
}
当从MDN网站运行完整版本时,它将按预期工作。当复制到我的本地计算机并从“file://”url(具有正确的图像相对路径)加载时,这会在drawImage…“source”行上抛出索引大小错误

图像通过img标签按预期加载

document.getElementById('source')
分配给变量,并将该变量传递给
drawImage
,表明该变量为非空且类宽为300(通过一个简单的
警报
),并且仍然抛出错误

ctx.drawImage(document.getElementById('frame'),0,0)线条是否正确绘制到画布


为什么我的本地计算机的行为与web版本不同?安全限制?(这里的新手,如果答案很简单,请道歉。)

您收到的是
索引大小错误
,因为您调用的
drawImage()
参数要么是负数,要么超出数据范围。在这种情况下,我们可以排除负值

相反,您可能看到错误,因为您要求的信息超出了源图像数据的维度。指定源坐标和目标坐标及标注时(如此处所述),允许传递目标标注边界以外的值(正数和负数)。可能会遇到麻烦的是源值

在你的例子中,我认为发生的事情是,你的源图像实际上不是
300px乘227px
,不管你在CSS中表示什么。即使图像可能在浏览器中显示得那么大,但加载到DOM中的图像对象中存储的实际像素数也会更小。因此,即使您对
drawImage()
的调用在为每个DOM元素指定大小的情况下具有有效的参数,您仍然需要
x
维度中的像素
33->137
,以及
y
维度中的像素
71->195
。其中一个(或两个)范围超出了源图像的尺寸。仔细检查源图像的实际大小

至于为什么在本地和网络执行之间会出现不同的行为,在请求映像时可能会遇到问题。除了通常无法在本地操作画布元素(除非设置特殊的开发环境或手动配置浏览器)之外,图像仍然必须“下载”到浏览器中,而不管其位置如何。浏览器中的图像采集是异步完成的,因此,鉴于您现在拥有的代码,当调用
draw()
函数时,无法保证两个(或其中一个)图像在内存中都可用

相反,您应该使用内置于图像元素中的
onload
回调函数。在本例中,由于您有两个图像,因此需要维护一个标志来确定何时加载这两个图像。您可以尝试以下方法:

<html>
<head>
<script type="application/x-javascript">
    var images_loaded = 0;

    function imageLoaded() {
        ++images_loaded;

        if (images_loaded == 2) {
            draw(); 
        }
    }

    function draw() {
        var ctx = document.getElementById('canvas').getContext('2d');
        ctx.drawImage(document.getElementById('frame'),0,0);
        ctx.drawImage(document.getElementById('source'),33,71,104,124,21,20,87,104);
    }
</script>
</head>
<body>
    <canvas id="canvas" width="150" height="150"></canvas>
    <img id="source" onload="imageLoaded();" src="images/rhino.jpg" width="300" height="227" alt="">
    <img id="frame" onload="imageLoaded();" src="images/picture_frame.png" width="132" height="150" alt="">
</body>
</html>

已加载的变量=0;
函数imageLoaded(){
++加载的图像;
如果(加载的图像=2){
draw();
}
}
函数绘图(){
var ctx=document.getElementById('canvas').getContext('2d');
ctx.drawImage(document.getElementById('frame'),0,0);
ctx.drawImage(document.getElementById('source'),33,71104124,21,20,87104);
}

请注意,调用rhino的
drawImage()
中的参数问题仍然存在于上述示例中;我不知道rhino.jpg图像的尺寸,因此我不建议更正。

您的服务器上和本地的图像是否相同?@c69:是的,相同,从MDN站点复制。图像必须通过HTTP加载到同一域中。不支持本地文件系统。如果在本地运行,则没有域。@Caspar Kleijne:Hrm。不过,颠倒“源”和“帧”线的顺序,“帧”线会在画布上渲染画框图像。我在努力理解。。。为什么它只适用于一个drawImage调用,而不适用于另一个调用?谢谢由于document.getElementById('source')为null或0乘0像素,因此猜测。问题确实出在图片大小上。负载发生得很好。非常感谢您的帮助,这对于学习加载模型和调试器的机制非常有用。@JoeZoller没问题!我很高兴我们能解决这个问题