【问题标题】:Canvas - IndexSizeError: Index or size is negative or greater than the allowed amountCanvas - IndexSizeError:索引或大小为负数或大于允许的数量
【发布时间】:2013-10-12 19:03:20
【问题描述】:

因此,在 Firefox 中,当在画布元素上使用 drawImage 时,我在控制台中收到此错误。

"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();

【问题讨论】:

    标签: javascript canvas


    【解决方案1】:

    当您使用剪辑时,您需要确保源区域在图像内(目标区域不需要,因为这将被画布剪辑)。

    因此,如果您添加限制控制,它应该可以工作。这是执行此操作的一种方法(在使用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:
    如果您需要将图像绘制得比您需要的更窄,而不是更改源区域,请更改目标区域。

    【讨论】:

    • 完美!肯又来救援了!
    • 也澄清一下。将 Math.round 应用于 .drawImage() 中使用的变量为我解决了这个问题。似乎 Firefox 不喜欢分数。
    • 您的值可能介于 0.5 和 1.0 之间,这确实将其四舍五入为 1,而 Firefox 会将 floor 它设为 0 - 这会触发该问题。作为浮点数 - 很好(经过测试)。
    • 小提琴链接不起作用。试试this fiddle
    【解决方案2】:

    宽度高度在您指定尺寸值时绘制的图像应大于或等于 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);
    

    【讨论】:

    • 你不是说 Math.max 吗?如果宽度或高度为正数,这将导致宽度和高度始终为 1。
    • @Tails 确实很有趣,这么长时间没人注意到它。
    【解决方案3】:

    为了帮助其他人,我在画布中遇到了同样的问题,我解决了考虑图像加载的问题,例如:

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

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题,但在 IESafari 中。我必须特别解决三件事:

      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) 我必须 round 宽度和高度值。由于其中一些是动态计算的,所以我有像 34.378 这样的值,这会导致问题。所以我不得不将它们四舍五入并传递 Integer 值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-27
        • 2016-05-07
        • 1970-01-01
        • 2020-04-15
        • 1970-01-01
        相关资源
        最近更新 更多