Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
394 views
in Technique[技术] by (71.8m points)

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

So in Firefox I'm getting this error in the console when using drawImage on a canvas element.

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

Everything is working fine in Chrome. Common causes for this I found were returning negative values or trying to draw the image to the canvas before the image is actually loaded. Neither of which seem to be the case. What am I missing here?

Any ideas would be greatly appreciated. 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();
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

When you are using clipping you need to make sure that the source region is within the image (not necessary for target as this will be clipped by canvas).

So if you add restriction control it should work. Here is one way of doing this (before using the clipping functionality of 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.

Tip 1:
Normally this also applies to x and y but as these are 0 here there is no need to check.

Tip 2:
If you need the image to be drawn narrower than you need to instead of changing source region, change the target region.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...