2013-10-12 32 views
19

因此,在canvas元素上使用drawImage時,在控制檯中出現此錯誤。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

澄清。在.drawImage()中使用的變量上應用Math.round爲我解決了這個問題。似乎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薩fari。有三件事我必須修復:

1)我必須手動設置圖像的widthheight

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值。

相關問題