Javascript错误:未捕获RangeError:无法执行' getImageData' on' CanvasRenderingContext2D':ImageData创建时内存不足

时间:2017-01-15 23:20:25

标签: javascript html out-of-memory

我正在编写一个简单的网页应用程序来绘制图片。我正在为洪水填充工具编写代码。该工具适用于填充小空间,但对于大空间,它将填充中途并停止。我检查了控制台,它被发送错误

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;
&#13;
&#13;

很抱歉代码片段,但我认为最好将其全部放入。有没有办法防止这些RangeErrors(不是SecurityErrors)? zoomed up slowed down visual

0 个答案:

没有答案