Firefox выдает исключение с HTML Canvas putImageData

Итак, я работал над этим небольшим экспериментом с javascript, и мне нужен был виджет для отслеживания его FPS. Я перенес виджет, который использовал с Actionscript 3, на Javascript, и, похоже, он отлично работает с Chrome/Safari, но в Firefox возникает исключение.

Это эксперимент:

Глубина резкости

Это ошибка:

[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;
}

}

Есть идеи? Заранее спасибо.


person Community    schedule 11.06.2009    source источник


Ответы (7)


Это ошибка в Firefox. Mozilla знает об этом. Вот обходной путь:

  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
    
person Roger    schedule 01.06.2010
comment
Все еще действительное исправление, только что столкнулся с этой проблемой с Mac FF4.0.1. - person Petteri H; 21.05.2011

Да, эта ошибка возникает при использовании (get|put)ImageData за краями холста.

Для решения этой проблемы я просто добавил некоторую логику отсечения, которая проверяет края рисуемой области относительно краев холста и обрезает их там, где это необходимо, рисуя только видимую область. Кажется, проблема устранена.

person bcherry    schedule 16.11.2009
comment
Это была и моя проблема. Вместо того, чтобы обрезать свои данные, я просто увеличил холст, и исключение перестало выдаваться. - person Jason Diamond; 05.07.2010

У меня была та же ошибка, потому что значение, которое я пытался установить для graphData.data[index], было строкой, а не целым числом. Чтобы исправить это, я преобразовал строку в целое число с помощью parseInt().

person Community    schedule 11.09.2009

У меня была аналогичная проблема с 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);
person Maksym Govorischev    schedule 16.02.2011

Я думаю, вам нужно указать еще два аргумента для putImageData: ширина и высота.

См. здесь

person Fabien Ménager    schedule 11.06.2009
comment
Вы правы, я ошибся в параметрах. Тем не менее, я изменил их, чтобы они использовали правильные параметры и все равно выдавали ту же ошибку. - person ; 11.06.2009

Я занимаюсь этой проблемой уже несколько дней (в firefox). Лучшая идея, которую я мог придумать, — это динамически удалять пиксели, которые исчезают с экрана. Я беспокоюсь, что для этого потребуется слишком много процессора. надеюсь, кто-то придумает лучшую идею :/

но повторюсь, я видел эту ошибку только тогда, когда putImageData пытается нарисовать ЛЮБОЙ пиксель за пределами периметра холста. например. любое значение x или y ‹ 0.

-- при втором чтении -- Похоже, вы уже изменяете размер данных изображения. Вы можете попробовать уменьшить размер изображения до 68 пикселей, если вы находитесь в контейнере размером 70 пикселей? Скорее всего не получится, но попробовать стоит..

person Jacksonkr    schedule 04.05.2010
comment
В одном из моих проектов я добавил функцию try/catch вокруг функции putImageData. В худшем случае вы получите кадр без изображения, а не сломанную программу. Это не решение, но да.. - person Jacksonkr; 05.05.2010

Это уже устарело, но это ТОЛЬКО вызывает у меня проблемы с FF на Windows. FF на Mac работает как надо.

person Jacksonkr    schedule 28.05.2010