Подтвердить что ты не робот

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

}

Любые идеи? Спасибо заранее.

4b9b3361

Ответ 1

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

  • Создайте новый холст в памяти:

    var spriteCanvas = document.createElement('canvas');
    
  • Установите высоту/ширину холста на высоту/ширину вашего изображения:

    spriteCanvas.setAttribute('width', 20);
    spriteCanvas.setAttribute('height', 20);
    
  • Поместите данные изображения в холст в позиции (0,0):

    spriteCanvas.getContext('2d').putImageData(imageData, 0, 0);
    
  • В контексте вашего основного холста нарисуйте свой холст-спрайт с помощью drawImage, используя любую позицию на экране или вне экрана:

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

Ответ 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: width и height.

Смотрите здесь

Ответ 6

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

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

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

Ответ 7

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