【问题标题】:Firefox throwing a exception with HTML Canvas putImageDataFirefox 使用 HTML Canvas putImageData 引发异常
【发布时间】:2010-11-02 04:36:48
【问题描述】:

所以我正在做这个小的 javascript 实验,我需要一个小部件来跟踪它的 FPS。我将我一直在使用 Actionscript 3 的小部件移植到 Javascript,它似乎在 Chrome/Safari 上运行良好,但在 Firefox 上抛出异常。

这是实验:

Depth of Field

这是错误:

[Exception... "An invalid or illegal string was specified"  code: "12" nsresult: "0x8053000c (NS_ERROR_DOM_SYNTAX_ERR)"  location: "http://mrdoob.com/projects/chromeexperiments/depth_of_field__debug/js/net/hires/debug/Stats.js Line: 105"]

抱怨的是这一行:

graph.putImageData(graphData, 1, 0, 0, 0, 69, 50);

这是“滚动”位图像素的糟糕代码。这个想法是我只在位图左侧绘制几个像素,然后在下一帧复制整个位图并将其粘贴到右侧的像素上。通常会抛出此错误,因为您粘贴的位图大于源并且超出了限制,但理论上不应该出现这种情况,因为我将 69 定义为要粘贴的矩形的宽度(即位图 70 像素宽)。

这是完整的代码:

var Stats = {
baseFps: null,

timer: null,
timerStart: null,
timerLast: null,
fps: null,
ms: null,

container: null,
fpsText: null,
msText: null,
memText: null,
memMaxText: null,

graph: null,
graphData: null, 

init: function(userfps)
{
    baseFps = userfps;

    timer = 0;
    timerStart = new Date() - 0;
    timerLast = 0; 
    fps = 0;
    ms = 0;

    container = document.createElement("div");
    container.style.fontFamily = 'Arial';
    container.style.fontSize = '10px';
    container.style.backgroundColor = '#000033';
    container.style.width = '70px';
    container.style.paddingTop = '2px';

    fpsText = document.createElement("div");
    fpsText.style.color = '#ffff00';
    fpsText.style.marginLeft = '3px';
    fpsText.style.marginBottom = '-3px';
    fpsText.innerHTML = "FPS:";
    container.appendChild(fpsText);

    msText = document.createElement("div");
    msText.style.color = '#00ff00';
    msText.style.marginLeft = '3px';
    msText.style.marginBottom = '-3px';
    msText.innerHTML = "MS:";
    container.appendChild(msText);

    memText = document.createElement("div");
    memText.style.color = '#00ffff';
    memText.style.marginLeft = '3px';
    memText.style.marginBottom = '-3px';
    memText.innerHTML = "MEM:";
    container.appendChild(memText);

    memMaxText = document.createElement("div");
    memMaxText.style.color = '#ff0070';
    memMaxText.style.marginLeft = '3px';
    memMaxText.style.marginBottom = '3px';
    memMaxText.innerHTML = "MAX:";
    container.appendChild(memMaxText);

    var canvas = document.createElement("canvas");
    canvas.width = 70;
    canvas.height = 50;
    container.appendChild(canvas);

    graph = canvas.getContext("2d");
    graph.fillStyle = '#000033';
    graph.fillRect(0, 0, canvas.width, canvas.height );

    graphData = graph.getImageData(0, 0, canvas.width, canvas.height);

    setInterval(this.update, 1000/baseFps);

    return container;
},

update: function()
{
    timer = new Date() - timerStart;

    if ((timer - 1000) > timerLast)
    {
        fpsText.innerHTML = "FPS: " + fps + " / " + baseFps;
        timerLast = timer;

        graph.putImageData(graphData, 1, 0, 0, 0, 69, 50);
        graph.fillRect(0,0,1,50);
        graphData = graph.getImageData(0, 0, 70, 50);

        var index = ( Math.floor(Math.min(50, (fps / baseFps) * 50)) * 280 /* 70 * 4 */ );
        graphData.data[index] = graphData.data[index + 1] = 256;

        index = ( Math.floor(Math.min(50, 50 - (timer - ms) * .5)) * 280 /* 70 * 4 */ );
        graphData.data[index + 1] = 256;            

        graph.putImageData (graphData, 0, 0);

        fps = 0;            
    }

    ++fps;

    msText.innerHTML = "MS: " + (timer - ms);
    ms = timer;
}

}

有什么想法吗?提前致谢。

【问题讨论】:

    标签: javascript html canvas


    【解决方案1】:

    这是 Firefox 中的一个错误。 Mozilla knows about it。这是解决方法:

    1. 制作一个新的内存画布:

      var spriteCanvas = document.createElement('canvas');
      
    2. 将画布的高度/宽度设置为图像的高度/宽度:

      spriteCanvas.setAttribute('width', 20);
      spriteCanvas.setAttribute('height', 20);
      
    3. 将图像数据放入画布的位置(0,0):

      spriteCanvas.getContext('2d').putImageData(imageData, 0, 0);
      
    4. 在主画布的上下文中,使用 drawImage 使用屏幕上或屏幕外的任何位置绘制画布精灵:

      context.drawImage(spriteCanvas, 50, 100); // clipping is allowed
      

    【讨论】:

    • 仍然是一个有效的修复方法,只是在 Mac FF4.0.1 中遇到了这个问题。
    【解决方案2】:

    是的,在画布边缘使用 (get|put)ImageData 时似乎会发生此错误。

    对于我遇到的这个问题,我只是添加了一些剪裁逻辑,检查要绘制的区域的边缘是否与画布的边缘相匹配,并在必要时对其进行剪裁,仅绘制可见区域。它似乎已经解决了这个问题。

    【讨论】:

    • 这也是我的问题。我没有剪裁我的数据,而是让画布更大并且不再抛出异常。
    【解决方案3】:

    我遇到了同样的错误,因为我尝试设置为 graphData.data[index] 的值是字符串而不是整数。 为了解决这个问题,我使用 parseInt() 将字符串转换为整数。

    【讨论】:

      【解决方案4】:

      当我尝试以这种方式在相同大小的画布上绘制图块时,我遇到了与 drawImage() 类似的问题:

      var image = new Image();
           image.onload = function() {
               context.drawImage(image, 0, 0, this.tileSize, this.tileSize);
             }
           image.src = this.baseURL + tileId;
      

      当我从调用中删除高度和宽度参数并使用它时,问题消失了:

      context.drawImage(image, 0, 0);
      

      【讨论】:

        【解决方案5】:

        我认为您需要为 putImageData 指定另外两个参数:宽度和高度。

        See here

        【讨论】:

        • 你是对的,我的参数错误。不过,我已经修改了它们,所以它使用了正确的参数并且仍然给出了同样的错误。
        【解决方案6】:

        我这几天一直在处理这个问题(在 Firefox 中)。我能想出的最好的主意是动态删除屏幕外的像素。我担心这样做会花费太多的cpu。希望有人想出一个更好的主意:/

        但重申一下,我只在 putImageData 尝试在画布外围绘制任何像素时看到此错误。例如。任何 x 或 y 值

        -- 在第二次阅读时-- 看起来您已经在调整图像数据的大小了。如果您在 70px 的容器中,您可以尝试将图像缩小到 68px?可能不会工作,但值得一试..

        【讨论】:

        • 在我的一个项目中,我在 putImageData 函数周围添加了一个 try/catch。最坏的情况是你得到一个没有图像的框架,而不是一个损坏的程序。这不是解决方案,但是是的..
        【解决方案7】:

        这已经过时了,但这只会给我在 Windows 上的 FF 问题。 mac 上的 FF 可以正常工作。

        【讨论】:

          猜你喜欢
          • 2011-07-13
          • 2021-12-21
          • 2017-10-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-02
          • 1970-01-01
          相关资源
          最近更新 更多