简体   繁体   中英

HTML5 canvas getImageData() can't work

When I use the getImageData() function to get the data of a image with chrome, it says that Uncaught IndexSizeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The source width is 0. Here is my code:

<!DOCTYPE html>
<html>
<head>
    <title>canvastest</title>
</head>
<body>
<img src="flower.jpg" hidden />
<canvas id="drawing" width="600" height="532">a drawing of something</canvas>
<script type="text/javascript" >
    var drawing = document.getElementById("drawing");
    if (drawing.getContext){
        var context = drawing.getContext("2d"),
            image = document.images[0],
            imageData,data,
            i,len,average,
            red,blue,green,alpha;

        image.onload = function(){
            context.drawImage(image,0,0);
        };

        imageData = context.getImageData(0,0,image.width,image.height);
        data = imageData.data;

        for (i=0,len=data.length;i<len;i+=4){
            red = data[i];
            green = data[i+1];
            blue = data[i+2];
            alpha = data[i+3];

            average = Math.floor((red + green + blue) / 3);

            data[i] = average;
            data[i+1] = average;
            data[i+2] = average;
        }

        imageData.data = data;
        context.putImageData(imageData,0,0);
    }
</script>
</body>
</html>

How could it happended? And how to fix it?

You are attaching an onload callback to actually draw the image to the canvas. But that only fires once the image is loaded in the DOM and it has to be fetched from the server. What makes you think any of that happens before you try to pull the image data from the canvas?

That's the problem when mixing synchronous and asynchronous code, and there are numerous techniques for getting around it. But I'd bet money if you set a break point in the debugger at the line the draws the image and the line that tries to read it that the latter will trigger before the former.

You either need to put the processing in your onload handler (not recommended because of the coupling) or use something like a promise to make sure the code that reads the data runs after the code that writes it.

That error message will also occur if you accidentally pass 0 to the width or height parameter:

context.getImageData(0, 0, 0, 0); //Throws an IndexSizeError

Regardless of whether it was due to a typo or a bad variable, passing 0 to the third or fourth parameter will always result in an error message of "The source width is 0." or "The source height is 0."

So instead of doing that, you should either reference the canvas's width/height directly:

context.getImageData(0, 0, context.canvas.clientWidth, context.canvas.clientHeight);

Or add a condition that checks to make sure that neither value is falsy:

if (my_width && my_height)
{
    context.getImageData(0, 0, my_width, my_height);
}

else
{
    alert('Invalid canvas width or height value!');
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM