2013-10-12 3 views
19

Итак, в Firefox я получаю эту ошибку в консоли при использовании drawImage в элементе canvas.Canvas - IndexSizeError: индекс или размер отрицательный или больше допустимой суммы

"IndexSizeError: Index or size is negative or greater than the allowed amount" 

Все работает отлично в Chrome. Общими причинами этого я возвращал отрицательные значения или пытался нарисовать изображение на холсте до того, как изображение загрузится. Ни один из них, похоже, не так. Что мне здесь не хватает?

Любые идеи были бы весьма признательны. http://jsfiddle.net/Ra9KQ/3/

var NameSpace = NameSpace || {}; 

NameSpace.Pixelator = (function() { 

    var _cache = { 
     'wrapper' : null, 
     'canvas' : null, 
     'ctx'  : null, 
     'img'  : new Image() 
    }, 

    _config = { 
     'canvasWidth'  : 250, 
     'canvasHeight'  : 250, 
     'isPlaying'  : false, 
     'distortMin'  : 3, 
     'distortMax'  : 100, 
     'distortValue'  : 100, // matches distortMax by default 
     'initDistortValue' : 3, 
     'speed'   : 2.5, 
     'delta'   : 2.5, // delta (+/- step), matches speed by default 
     'animation'  : null, 
     'origImgWidth'  : null, 
     'origImgHeight' : null, 
     'imgHeightRatio' : null, 
     'imgWidthRatio' : null, 
     'newImgWidth'  : null, 
     'newImgHeight'  : null 
    }, 

    _init = function _init() { 

     _setupCache(); 
     _setupCanvas(); 
     _setupImage(); 

    }, 

    _setupCache = function _setupCache() { 

     _cache.wrapper = $('#dummy-wrapper'); 
     _cache.canvas = document.getElementById('dummy-canvas'); 
     _cache.ctx = _cache.canvas.getContext('2d'); 

    }, 

    _setupCanvas = function _setupCanvas() { 

     _cache.ctx.mozImageSmoothingEnabled = false; 
     _cache.ctx.webkitImageSmoothingEnabled = false; 
     _cache.ctx.imageSmoothingEnabled = false; 

    }, 

    _setupImage = function _setupImage() { 

     _cache.img.onload = function() { 

      _adjustImageScale(); 
      _pixelate(); 
      _assignEvents(); 

     }; 

     _cache.img.src = _cache.canvas.getAttribute('data-src'); 

    }, 

    _adjustImageScale = function _adjustImageScale() { 

     var scaledHeight, 
      scaledWidth; 

     _config.origImgWidth = _cache.img.width; 
     _config.origImgHeight = _cache.img.height; 
     _config.imgHeightRatio = _config.origImgHeight/_config.origImgWidth; 
     _config.imgWidthRatio = _config.origImgWidth/_config.origImgHeight; 

     scaledHeight = Math.round(250 * _config.imgHeightRatio); 
     scaledWidth = Math.round(250 * _config.imgWidthRatio); 

     if (scaledHeight < 250) { 

      _config.newImgHeight = 250; 
      _config.newImgWidth = Math.round(_config.newImgHeight * _config.imgWidthRatio); 

     } else if (scaledWidth < 250) { 

      _config.newImgWidth = 250; 
      _config.newImgHeight = Math.round(_config.newImgWidth * _config.imgHeightRatio); 

     } 

    }, 

    _assignEvents = function _assignEvents() { 

     _cache.wrapper.on('mouseenter', _mouseEnterHandler); 
     _cache.wrapper.on('mouseleave', _mouseLeaveHandler); 

    }, 

    _mouseEnterHandler = function _mouseEnterHandler(e) { 

     _config.delta = -_config.speed; 

     if (_config.isPlaying === false) { 
      _config.isPlaying = true; 
      _animate(); 
     } 

    }, 

    _mouseLeaveHandler = function _mouseLeaveHandler(e) { 

     _config.delta = _config.speed; 

     if (_config.isPlaying === false) { 
      _config.isPlaying = true; 
      _animate(); 
     } 

    }, 

    _pixelate = function _pixelate(val) { 

     var size = val ? val * 0.01 : 1, 
      w = Math.ceil(_config.newImgWidth * size), 
      h = Math.ceil(_config.newImgHeight * size); 

     console.log('w: ' + w,'h: ' + h,'_config.newImgWidth: ' + _config.newImgWidth,'_config.newImgHeight: ' + _config.newImgHeight); 

     _cache.ctx.drawImage(_cache.img, 0, 0, w, h); 

     _cache.ctx.drawImage(_cache.canvas, 0, 0, w, h, 0, 0, _config.canvasWidth, _config.canvasHeight); 

    }, 

    _animate = function _animate() { 

     // increase/decrese with delta set by mouse over/out 
     _config.distortValue += _config.delta; 

     if (_config.distortValue >= _config.distortMax || _config.distortValue <= _config.distortMin) { 

      _config.isPlaying = false; 
      cancelAnimationFrame(_config.animation); 
      return; 

     } else { 

      // pixelate 
      _pixelate(_config.distortValue); 
      _config.animation = requestAnimationFrame(_animate); 

     } 

    }; 

    return { 
     init: _init 
    }; 

})(); 

NameSpace.Pixelator.init(); 

ответ

11

При использовании отсечения вы должны убедиться, что область источника находится в пределах изображения (не обязательно для цели, как это будет обрезано холст).

Так что если вы добавите контроль ограничения, он должен работать. Вот один из способов сделать это (перед использованием функции отсечения drawImage):

if (w > _config.canvasWidth) w = _config.canvasWidth; 
if (h > _config.canvasHeight) h = _config.canvasHeight; 

_cache.ctx.drawImage(_cache.canvas, 0, 0, w, h, 
         0, 0, _config.canvasWidth, _config.canvasHeight); 

Modified fiddle here.

Совет 1:
Обычно это также относится к x и y, но поскольку они 0, здесь нет необходимости проверять.

Совет 2:
Если вам нужно, чтобы изображение было нарисовано уже, чем вам нужно, вместо изменения области источника, измените целевую область.

+0

Отлично! Кен снова спасается! – brandongray

+4

Чтобы уточнить. Применение Math.round для переменных, используемых в .drawImage(), исправило эту проблему для меня. Кажется, Firefox не понравился фракционированный номер. –

+0

Вероятно, вы имели значение от 0,5 до 1,0, что округлоло его до 1, в то время как Firefox «погладил» его так, что это будет 0 - что вызывает эту проблему. Как плавающие числа - отлично (проверено). – moka

6

Ширина и Высота изображений вы рисуете, когда вы определяете размер значение должен быть больше или равен 1. Также для преимуществ производительности floor все значения, которые вы передаете ему.
Если ширина и/или высота 0, то это приведет к:

IndexSizeError: Index or size is negative or greater than the allowed amount 

В Firefox:

width = Math.max(1, Math.floor(width)); 
height = Math.max(1, Math.floor(height)); 
ctx.drawImage(image, x, y, width, height); 
+3

Разве вы не имеете в виду Math.max? Это приведет к тому, что ширина и высота всегда будут равны 1, если ширина или высота будут положительными. – Tails

+0

@ На самом деле, это забавно, что никто не заметил его так долго. – moka

1

Чтобы помочь другим, у меня была та же проблема в полотне и я решаю принимая во внимание на изображение нагрузки, например:

var image = new Image(); 
image.crossOrigin = "use-credentials"; 
image.onload = function(){ 
    // here canvas behavior 
}; 
image.src = imgSrc; 
0

у меня была такая же проблема, но в IE и Sa fari. В частности, было три вещи, которые мне пришлось исправить:

1) Я должен был установить и height изображения вручную.

var image = new Image(); 
... 
image.width = 34; 
image.height = 34; 

2) Я должен был избежать использования отрицательного смещения при создании ol.style.Icon. В этом случае мне пришлось менять значок SVG, но это в значительной степени зависит от вашего значка.Таким образом, это вызвало бы исключение из-за отрицательного смещения:

var icon = new ol.style.Style({ 
    "image": new ol.style.Icon({ 
     ... 
     "offset": [0, -50] 
    }) 
}); 

3) Я должен был раунде ширина и высота значений. Поскольку некоторые из них были рассчитаны динамически, у меня были такие значения, как 34.378, которые вызывали проблемы. Поэтому мне пришлось округлить их и передать значение Integer.

Смежные вопросы

 Смежные вопросы