【问题标题】:canvasContext.fillRect throws NS_ERROR_FAILURE exception in FirefoxcanvasContext.fillRect 在 Firefox 中抛出 NS_ERROR_FAILURE 异常
【发布时间】:2012-09-28 14:44:16
【问题描述】:

我正在尝试在页面顶部绘制一个巨大的画布矩形(某种灯箱背景),代码非常简单:

var el = document.createElement('canvas');
el.style.position = 'absolute';
el.style.top  = 0;
el.style.left = 0;
el.style.zIndex = 1000;
el.width  = window.innerWidth + window.scrollMaxX;
el.height = window.innerHeight + window.scrollMaxY;

...
document.body.appendChild(el);

// and later

var ctx = el.getContext("2d");
ctx.fillStyle = "rgba(0, 0, 0, 0.4)";
ctx.fillRect(0, 0, el.width, el.height);

有时(不总是)最后一行抛出:

组件返回失败码:0x80004005 (NS_ERROR_FAILURE) [nsIDOMCanvasRenderingContext2D.fillRect]

我一直在猜测是否会因为图像大小或画布下方的内容类型(例如嵌入视频播放)而发生这种情况,但显然不是。

所以我正在寻找有关如何隔离和/或解决此问题的任何想法。

【问题讨论】:

    标签: javascript firefox canvas


    【解决方案1】:

    查看nsIDOMCanvasRenderingContext2D.fillRect() implementation(并查看它调用的函数)——返回NS_ERROR_FAILURE 的条件并不多。只有在 EnsureSurface()mThebes->CopyPath() 失败时才会发生这种情况。 EnsureSurface() 中的以下两行很可能是您的问题的根源:

    // Check that the dimensions are sane
    if (gfxASurface::CheckSurfaceSize(gfxIntSize(mWidth, mHeight), 0xffff)) {
    

    这里检查的是什么:

    • 画布的宽度和高度都不能超过 65535 像素。
    • 在 Mac OS X 上高度不能超过 32767 像素(平台限制)。
    • 画布数据 (width * height * 4) 的大小不能超过 2 GB。

    如果违反了这些条件中的任何一个,EnsureSurface() 将返回 false 并因此产生您所看到的异常。请注意,以上是可以随时更改的实现细节,您不应依赖它们。但他们可能会让您了解您的代码违反了哪些特定限制。

    【讨论】:

    • 不幸的是,即使在非常小的矩形上也会出现相同的错误。像 ctx.fillRect(0, 0, 100, 100);
    • @nweb:此代码不检查矩形大小,它检查画布的大小...在画布超过大小限制的情况下,任何绘制尝试都会失败并出现类似的异常。
    • 谢谢!终于找到了解决我的问题的方法。确实是因为一块巨大的画布。
    • 难以置信,这没有更好的记录:-/
    • @JamesCat:这些只是实施细节,可能会发生变化(过去四年可能已经发生了重大变化)。最后,你得到的可以总结为:“画布或单个操作数的大小可能会受到限制,不要指望大尺寸总是有效的。”
    【解决方案2】:

    您可以应用 try-catch 逻辑。 Firefox 似乎是唯一表现得有点奇怪的浏览器。

    el.width  = window.innerWidth + window.scrollMaxX;
    el.height = window.innerHeight + window.scrollMaxY;
    
    // try first to draw something to check that the size is ok
    try
    {
      var ctx = el.getContext("2d");
      ctx.fillRect(0, 0, 1, 1);
    }
    
    // if it fails, decrease the canvas size
    catch(err)
    {
      el.width = el.width - 1000;
      el.height = el.height - 1000;
    }
    

    我还没有找到任何变量来告诉最大画布大小是多少。它因浏览器和设备而异。

    检测最大画布大小的唯一跨浏览器方法似乎是减小画布大小的循环,例如。 100px,直到它不产生错误。我测试了一个循环,这是检测最大画布大小的相当快的方法。因为其他浏览器在尝试在过大的画布上绘制时不会抛出错误,所以最好尝试绘制例如。 red rect 并读取一个像素并检查它是否为红色。

    为了最大限度地提高检测性能:
    - 循环时,画布应该在 DOM 之外以最大化速度
    - 将起始大小设置为众所周知的最大值,似乎是 32,767 像素(SO:Maximum size of a <canvas> element
    - 您可以创建一个更智能的循环来分叉最大尺寸:例如使用第一个更大的减小步骤(例如 1000 像素),当达到可接受的尺寸时,尝试将尺寸增加 500 像素。如果这是可接受的尺寸,则增加 250 像素,依此类推。这样,应该在最少的试验中找到最大值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-18
      • 1970-01-01
      • 2012-01-24
      • 2013-05-24
      • 2013-03-04
      • 1970-01-01
      • 2011-05-30
      • 2017-02-14
      相关资源
      最近更新 更多