绘图到 canvas 总是有模糊的结果
Drawing to canvas always has blurry results
我已经搜索了很多网页和整个 Whosebug,但还没有找到我的问题的答案。我想制作一个简单的图块编辑器,它要求我能够逐个像素地编辑 canvas。每个图块为 8 像素 x 8 像素。我有我的 HTML 属性和 CSS 来使用 8 x 8 像素。我试过下面的方法,也试过其他各种方法,包括 html2canvas。我总是得到模糊的结果。下面是一些重现此问题的测试代码。
我正在使用一本 Chromebook (Toshiba Chromebook 2) 在最新的稳定版本上进行测试。我还使用 Nexus 7 (2013) 平板电脑和 LG G3 Android 电池 phone 进行了测试,结果相同。我在每台设备上都使用 Chrome 浏览器。
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>test</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<style>
body {background:white;}
</style>
<script>
$(document).ready(function() {
drawPixel('canvas0', 0, 0, 255, 0, 0, 255);
drawPixel('canvas0', 0, 1, 255, 0, 0, 255);
drawPixel('canvas0', 0, 2, 255, 0, 0, 255);
drawPixel('canvas0', 0, 3, 255, 0, 0, 255);
drawPixel('canvas0', 0, 4, 255, 0, 0, 255);
function drawPixel (canvasname, x, y, r, g, b, a) {
// console.log('values passed to drawPixel:', canvas, x, y, r, g, b, a);
var canvas = document.getElementById(canvasname);
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext("2d");
ctx.translate(0.5, 0.5) ;
var canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
var index = ((x + y) * canvasWidth) * 4;
console.log('1',canvasData);
canvasData.data[index + 0] = r;
canvasData.data[index + 1] = g;
canvasData.data[index + 2] = b;
canvasData.data[index + 3] = a;
console.log('2',canvasData);
ctx.putImageData(canvasData, 0, 0);
}
});
</script>
</head>
<body>
<canvas id="canvas0" width="8" height="8" style="width:8px;height:8px;"></canvas>
</body>
</html>
下面更新了代码
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>test</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<style>
body {background:white;}
</style>
<script>
$(document).ready(function() {
var canvas = document.getElementById('canvas0');
var ctx = canvas.getContext("2d");
ctx.translate(0.5, 0.5);
drawPixel(ctx, 0, 0, 255, 0, 0, 255);
drawPixel(ctx, 0, 1, 255, 0, 0, 255);
drawPixel(ctx, 0, 2, 255, 0, 0, 255);
drawPixel(ctx, 0, 3, 255, 0, 0, 255);
drawPixel(ctx, 0, 4, 255, 0, 0, 255);
function drawPixel(ctx, x, y, r, g, b, a) {
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a + ")";
ctx.fillRect(x, y, 1, 1);
}
});
</script>
</head>
<body>
<canvas id="canvas0" width="8" height="8" style="width:8px;height:8px;"></canvas>
</body>
</html>
您应该重写 drawPixel 方法以仅绘制一个像素。此处无需使用 ImageData 对象,并且转换在任何情况下都不起作用。
我的建议是这样做(保留签名):
function drawPixel (canvasname, x, y, r, g, b, a) {
// these should in parent or global scope, just pass in the context
var canvas = document.getElementById(canvasname);
var ctx = canvas.getContext("2d");
// set color, note alpha here is a value in the range [0, 1]
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")";
ctx.fillRect(x, y, 1, 1);
}
为了使像素更清晰,在全局范围内使用翻译(并且只使用一次),例如(非签名兼容版本):
var canvas = document.getElementById("test");
var ctx = canvas.getContext("2d");
drawPixel(ctx, 0, 0, 255, 0, 0, 255);
drawPixel(ctx, 0, 1, 255, 0, 0, 255);
drawPixel(ctx, 0, 2, 0, 255, 0, 255); // to show more clearly
drawPixel(ctx, 0, 3, 255, 0, 0, 255);
drawPixel(ctx, 0, 4, 255, 0, 0, 255);
// show image with standard interpolation (bilinear)
ctx.drawImage(canvas, 0, 0, 8, 8, 8, 0, 64, 64);
// show image enlarged using nearest-neighbor
ctx.imageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.drawImage(canvas, 0, 0, 8, 8, 50, 0, 64, 64);
function drawPixel(ctx, x, y, r, g, b, a) {
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")";
ctx.fillRect(x, y, 1, 1);
}
<canvas id="test" width=130 height=64></canvas>
此外,您可以删除标签内的样式属性。 canvas 元素将采用给定的大小 width/height.
我已经搜索了很多网页和整个 Whosebug,但还没有找到我的问题的答案。我想制作一个简单的图块编辑器,它要求我能够逐个像素地编辑 canvas。每个图块为 8 像素 x 8 像素。我有我的 HTML 属性和 CSS 来使用 8 x 8 像素。我试过下面的方法,也试过其他各种方法,包括 html2canvas。我总是得到模糊的结果。下面是一些重现此问题的测试代码。
我正在使用一本 Chromebook (Toshiba Chromebook 2) 在最新的稳定版本上进行测试。我还使用 Nexus 7 (2013) 平板电脑和 LG G3 Android 电池 phone 进行了测试,结果相同。我在每台设备上都使用 Chrome 浏览器。
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>test</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<style>
body {background:white;}
</style>
<script>
$(document).ready(function() {
drawPixel('canvas0', 0, 0, 255, 0, 0, 255);
drawPixel('canvas0', 0, 1, 255, 0, 0, 255);
drawPixel('canvas0', 0, 2, 255, 0, 0, 255);
drawPixel('canvas0', 0, 3, 255, 0, 0, 255);
drawPixel('canvas0', 0, 4, 255, 0, 0, 255);
function drawPixel (canvasname, x, y, r, g, b, a) {
// console.log('values passed to drawPixel:', canvas, x, y, r, g, b, a);
var canvas = document.getElementById(canvasname);
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext("2d");
ctx.translate(0.5, 0.5) ;
var canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
var index = ((x + y) * canvasWidth) * 4;
console.log('1',canvasData);
canvasData.data[index + 0] = r;
canvasData.data[index + 1] = g;
canvasData.data[index + 2] = b;
canvasData.data[index + 3] = a;
console.log('2',canvasData);
ctx.putImageData(canvasData, 0, 0);
}
});
</script>
</head>
<body>
<canvas id="canvas0" width="8" height="8" style="width:8px;height:8px;"></canvas>
</body>
</html>
下面更新了代码
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>test</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<style>
body {background:white;}
</style>
<script>
$(document).ready(function() {
var canvas = document.getElementById('canvas0');
var ctx = canvas.getContext("2d");
ctx.translate(0.5, 0.5);
drawPixel(ctx, 0, 0, 255, 0, 0, 255);
drawPixel(ctx, 0, 1, 255, 0, 0, 255);
drawPixel(ctx, 0, 2, 255, 0, 0, 255);
drawPixel(ctx, 0, 3, 255, 0, 0, 255);
drawPixel(ctx, 0, 4, 255, 0, 0, 255);
function drawPixel(ctx, x, y, r, g, b, a) {
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a + ")";
ctx.fillRect(x, y, 1, 1);
}
});
</script>
</head>
<body>
<canvas id="canvas0" width="8" height="8" style="width:8px;height:8px;"></canvas>
</body>
</html>
您应该重写 drawPixel 方法以仅绘制一个像素。此处无需使用 ImageData 对象,并且转换在任何情况下都不起作用。
我的建议是这样做(保留签名):
function drawPixel (canvasname, x, y, r, g, b, a) {
// these should in parent or global scope, just pass in the context
var canvas = document.getElementById(canvasname);
var ctx = canvas.getContext("2d");
// set color, note alpha here is a value in the range [0, 1]
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")";
ctx.fillRect(x, y, 1, 1);
}
为了使像素更清晰,在全局范围内使用翻译(并且只使用一次),例如(非签名兼容版本):
var canvas = document.getElementById("test");
var ctx = canvas.getContext("2d");
drawPixel(ctx, 0, 0, 255, 0, 0, 255);
drawPixel(ctx, 0, 1, 255, 0, 0, 255);
drawPixel(ctx, 0, 2, 0, 255, 0, 255); // to show more clearly
drawPixel(ctx, 0, 3, 255, 0, 0, 255);
drawPixel(ctx, 0, 4, 255, 0, 0, 255);
// show image with standard interpolation (bilinear)
ctx.drawImage(canvas, 0, 0, 8, 8, 8, 0, 64, 64);
// show image enlarged using nearest-neighbor
ctx.imageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.drawImage(canvas, 0, 0, 8, 8, 50, 0, 64, 64);
function drawPixel(ctx, x, y, r, g, b, a) {
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")";
ctx.fillRect(x, y, 1, 1);
}
<canvas id="test" width=130 height=64></canvas>
此外,您可以删除标签内的样式属性。 canvas 元素将采用给定的大小 width/height.