我正在编写一个简单的网页应用程序来绘制图片。我正在为洪水填充工具编写代码。该工具适用于填充小空间,但对于大空间,它将填充中途并停止。我检查了控制台,它被发送错误
Uncaught RangeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': Out of memory at ImageData creation
function move(e, s, c){
if(!e.value)
e.style.right = s + "px";
else
e.style.right = c + "px";
e.value = !e.value;
}
function fixGradient(){
var color1 = 238;
var color2 = 221;
var y = 42;
var height = 50;
var slope = (color1 - color2) / (0 - height);
var intercept = color1 - ((slope) * y);
var screenHeight = window.innerHeight;
var bottomColor = Math.round(slope * screenHeight + intercept);
var color = "rgb(" + bottomColor + ", " + bottomColor + ", " + bottomColor + ")";
document.getElementById("panel").style.backgroundImage = "linear-gradient(#FCFCFC, " + color + ")";
}
var colorValue = "#000000";
function setColor(color){
ctx.fillStyle = color;
ctx.strokeStyle = color;
colorValue = color.toUpperCase();
}
var con = 1 / Math.sqrt(2);
var mouseDown = false;
var click = false;
var size = 2;
var position = [0, 0, 0, 0, 0, 0, 0, 0];
var ctx;
var tool = 0;
var canvas;
var busy = false;
function set(t){
tool = Number(t);
}
function getFile(){
document.getElementById("bgchooser").click();
}
function setBG(e){
/*
var f = new FileReader();
f.readAsDataURL( el("f").files[0] );
f.onload = function(e){
var b64 = e.target.result;
el("loc").value = b64;
change();
}
*/
var file = e.files[0];
var reader = new FileReader(file);
reader.readAsDataURL(file);
reader.onload = function(r){
var b64 = r.target.result;
canvas.style.backgroundImage = "url('" + b64 + "')";
}
}
window.onload = function(){
canvas = document.getElementById("c");
canvas.addEventListener("mousedown", function(){
mouseDown = true;
position[6] = position[0];
position[7] = position[1];
});
window.addEventListener("mouseup", function(){
mouseDown = false;
});
window.addEventListener("keydown", function(e){
var keyCode = e.keyCode || e.which;
if(keyCode == 82){
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
});
canvas.addEventListener("click", function(){
click = true;
});
window.addEventListener("mousemove", function(e){
position[4] = position[2];
position[5] = position[3];
position[2] = position[0];
position[3] = position[1];
position[0] = e.clientX;
position[1] = e.clientY;
});
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx = canvas.getContext("2d");
var scale = [1, 1];
setInterval(function(){
fixGradient();
size = Number(document.getElementById("size").value) * con;
document.getElementById("display").style.height = size + "px";
document.getElementById("liveDisplay").innerHTML = size + "px";
ctx.lineWidth = size;
scale[0] = canvas.width / window.innerWidth;
scale[1] = canvas.height / window.innerHeight;
if(tool==0){
canvas.style.cursor = "url(eyedrop.cur), crosshair";
if(mouseDown){
ctx.beginPath();
ctx.moveTo(position[4] * scale[0], position[5] * scale[1]);
ctx.lineTo(position[2] * scale[0], position[3] * scale[1]);
ctx.lineTo(position[0] * scale[0], position[1] * scale[1]);
ctx.stroke();
//fill gaps
ctx.beginPath();
ctx.arc(position[0] * scale[0], position[1] * scale[1], size / 2, 0, 2 * Math.PI, true);
ctx.fill();
} else {
//if(click&&position[6]==position[0]&&position[7]==position[1]) ctx.fillRect(position[0] * scale[0] - (size / 2), position[1] * scale[1] - (size / 2), size, size);
position[2] = position[0];
position[3] = position[1];
position[4] = position[0];
position[5] = position[1];
click = false;
}
} else if(tool==1){
if(mouseDown){
ctx.clearRect(position[0] * scale[0] - size / 2, position[1] * scale[1] - size / 2, size, size);
}
} else if(tool==2){
var x = position[0];
var y = position[1];
var index = x * 4 + y * canvas.width * 4;
var imgdata = canvas.getImageData(0, 0, canvas.width, canvas.height);
var data = imgdata.data;
} else if(tool==3){
//paint bucket may be taken out or not left in
var x = position[0];
var y = position[1];
var idata;
try{
idata = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
} catch(e){
setTimeout(100);
idata = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
}
var idataindex = 4 * (x + y * canvas.width)
if(mouseDown){
flood(canvas, ctx, x, y, [idata[idataindex], idata[idataindex + 1], idata[idataindex + 2], idata[idataindex + 3]], [255, 0, 0, 255]);
mouseDown = false;
}
}
}, 0);
}
function getPixel(data, x, y, width){
return [data[4 * (y * width + x)], data[4 * (y * width + x) + 1], data[4 * (y * width + x) + 2], data[4 * (y * width + x) + 3]];
}
function scan(x, y, o, n, c, t){
console.log("Scanning: (" + x + ", " + y + "), old=new: " + (o==n) + ", old: " + o + ", new: " + n);
if(o != n){
var data = t.getImageData(0, 0, c.width, c.height).data;
if(y!=0){
var top = getPixel(data, x, y - 1, c.width);
if(top[0] == o[0] && top[1] == o[1] && top[2] == o[2] && top[3] == o[3]){
t.fillRect(x, y - 1, 1, 1);
scan(x, y - 1, o, n, c, t);
}
}
if(x!=c.width){
var right = getPixel(data, x + 1, y, c.width);
if(right[0] == o[0] && right[1] == o[1] && right[2] == o[2] && right[3] == o[3]){
t.fillRect(x + 1, y, 1, 1);
scan(x + 1, y, o, n, c, t);
}
}
if(x!=0){
var left = getPixel(data, x - 1, y, c.width);
if(left[0] == o[0] && left[1] == o[1] && left[2] == o[2] && left[3] == o[3]){
t.fillRect(x - 1, y, 1, 1);
scan(x - 1, y, o, n, c, t);
}
}
if(y!=c.height){
var bottom = getPixel(data, x, y + 1, c.width);
if(bottom[0] == o[0] && bottom[1] == o[1] && bottom[2] == o[2] && bottom[3] == o[3]){
t.fillRect(x, y + 1, 1, 1);
scan(x, y + 1, o, n, c, t);
}
}
}
}
function flood(c, cctx, x, y, oldColor, newColor){
if(!busy){
busy = true;
var oldFill = ctx.fillStyle;
//ctx.fillStyle = "rgb(" + newColor[0] + ", " + newColor[1] + ", " + newColor[2] + ")";
ctx.fillRect(x, y, 1, 1);
scan(x, y, oldColor, newColor, c, ctx);
busy = false;
}
}

body{
margin: 0px;
overflow: hidden;
}
.canvas{
width: 100%;
height: 100%;
position: absolute;
background: white;
cursor: url(aero_pen.cur), crosshair;
}
.button{
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
border: 1px solid #808080;
border-right: medium none;
box-sizing: border-box;
background-image: linear-gradient(#EEEEEE, #DDDDDD);
width: 50px;
height: 50px;
position: absolute;
top: 40px;
right: 0px;
transition: right 0.2s;
z-index: 11;
}
.panel{
border-left: 1px solid #808080;
width: 251px;
box-sizing: border-box;
z-index: 10;
position: absolute;
top: 0px;
right: -251px;
background-image: linear-gradient(#FCFCFC, #262626);
height: 100%;
transition: right 0.2s;
padding-left: 20px;
padding-top: 10px;
padding-right: 20px;
overflow: auto;
padding-bottom: 20px;
}
label{
font-family: Tahoma;
}
input[type=color], input[type=range], input[type=button]{
width: calc(100% - 6px);
}
.display{
width: 100%;
height: 2px;
background-color: black;
border-radius: 4px;
}
select{
width: 100%;
padding: 4px;
font-weight: bold;
appearance: button;
border: 1px inset #808080;
}
option:hover{
background-color: #808080;
color: white;
}
.hidden{
display: none;
}

<!DOCTYPE HTML>
<html>
<head>
<title>Art Program</title>
</head>
<body>
<canvas id="c" class="canvas"></canvas>
<div class="expand button" onclick="move(this, 250, 0); move(document.getElementById('panel'), 0, -251);" value="false"></div>
<div class="panel" value="false" id="panel">
<div>
<label>Color: </label>
<br/>
<input type="color" value="black" onchange="setColor(this.value);"/>
</div>
<hr/>
<div>
<label>Tool: </label>
<br/>
<input type="radio" name="tool" value="0" checked="true" onclick="set(this.value);"/>
<label>Pencil</label><br/>
<input type="radio" name="tool" value="1" onclick="set(this.value);"/>
<label>Eraser</label><br/>
<input type="radio" name="tool" value="2" onclick="set(this.value);"/>
<label>Eyedropper</label><br/>
<input type="radio" name="tool" value="3" onclick="set(this.value);"/>
<label>Flood Fill</label>
</div>
<hr/>
<div>
<label>Background: </label>
<br/>
<input type="file" class="hidden" id="bgchooser" onchange="setBG(this);"/>
<input type="button" value="Choose Background" onclick="getFile();"/>
</div>
<hr/>
<div>
<label>Language: </label>
<br/>
<select>
<option>বাঙালি</option>
<option>English (UK)</option>
<option>English (US)</option>
<option>Español</option>
<option>فُصْحَى</option>
<option>汉语</option>
<option>漢語</option>
<option>हिन्दी</option>
<option>português</option>
</select>
</div>
<hr/>
<div>
<label>Size: </label>
<br/>
<input type="range" min="1" max="100" value="2" id="size"/>
<br/>
<label id="liveDisplay">2</label>
<div class="display" id="display"></div>
</div>
</div>
</body>
</html>
&#13;
很抱歉代码片段,但我认为最好将其全部放入。有没有办法防止这些RangeErrors(不是SecurityErrors)? zoomed up slowed down visual