如何在画布上启用抗锯齿。
以下代码未绘制平滑线:
var context = mainCanv.getContext("2d");
if (context) {
context.moveTo(0,0);
context.lineTo(100,75);
context.strokeStyle = "#df4b26";
context.lineWidth = 3;
context.stroke();
}
答案 0 :(得分:37)
您可以按半像素距离翻译画布。
ctx.translate(0.5, 0.5);
最初是物理像素之间的画布定位点。
答案 1 :(得分:24)
无法打开或关闭消除锯齿,并且由浏览器控制。
答案 2 :(得分:20)
我还没有必要打开反别名,因为默认情况下它已打开,但我需要将其关闭。如果它可以关闭它也可以打开。
ctx.imageSmoothingEnabled = true;
我通常在我的画布RPG上工作时将其关闭,所以当我放大图像时看起来并不模糊。
答案 3 :(得分:11)
现在是2018年,我们终于有了廉价的方法来做点什么......
实际上,由于2d上下文API现在具有filter
属性,并且此过滤器属性可以接受SVGFilters,因此我们可以构建一个SVGFilter,它将仅保留完全不透明的像素,并且从而消除了默认的抗锯齿。
因此,它本身不会停用抗锯齿功能,但在实现和性能方面都提供了一种廉价的方法,可以在绘制时删除所有半透明像素。
我不是SVGFilters的专家,因此可能有更好的方法,但是对于这个例子,我将使用<feComponentTransfer>
节点仅抓取完全不透明的像素。
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#ABEDBE';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = 'black';
ctx.font = '14px sans-serif';
ctx.textAlign = 'center';
// first without filter
ctx.fillText('no filter', 60, 20);
drawArc();
drawTriangle();
// then with filter
ctx.setTransform(1, 0, 0, 1, 120, 0);
ctx.filter = 'url(#remove-alpha)';
// and do the same ops
ctx.fillText('no alpha', 60, 20);
drawArc();
drawTriangle();
// to remove the filter
ctx.filter = 'none';
function drawArc() {
ctx.beginPath();
ctx.arc(60, 80, 50, 0, Math.PI * 2);
ctx.stroke();
}
function drawTriangle() {
ctx.beginPath();
ctx.moveTo(60, 150);
ctx.lineTo(110, 230);
ctx.lineTo(10, 230);
ctx.closePath();
ctx.stroke();
}
// unrelated
// simply to show a zoomed-in version
var zCtx = zoomed.getContext('2d');
zCtx.imageSmoothingEnabled = false;
canvas.onmousemove = function drawToZoommed(e) {
var x = e.pageX - this.offsetLeft,
y = e.pageY - this.offsetTop,
w = this.width,
h = this.height;
zCtx.clearRect(0,0,w,h);
zCtx.drawImage(this, x-w/6,y-h/6,w, h, 0,0,w*3, h*3);
}
&#13;
<svg width="0" height="0" style="position:absolute;z-index:-1;">
<defs>
<filter id="remove-alpha" x="0" y="0" width="100%" height="100%">
<feComponentTransfer>
<feFuncA type="discrete" tableValues="0 1"></feFuncA>
</feComponentTransfer>
</filter>
</defs>
</svg>
<canvas id="canvas" width="250" height="250" ></canvas>
<canvas id="zoomed" width="250" height="250" ></canvas>
&#13;
对于那些不想在其DOM中附加<svg>
元素的人,您还可以将其另存为外部svg文件,并将filter
属性设置为{{1 }}
答案 4 :(得分:8)
这是一种解决方法,需要您逐个像素地绘制线条,但会阻止抗锯齿。
// some helper functions
// finds the distance between points
function DBP(x1,y1,x2,y2) {
return Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
// finds the angle of (x,y) on a plane from the origin
function getAngle(x,y) { return Math.atan(y/(x==0?0.01:x))+(x<0?Math.PI:0); }
// the function
function drawLineNoAliasing(ctx, sx, sy, tx, ty) {
var dist = DBP(sx,sy,tx,ty); // length of line
var ang = getAngle(tx-sx,ty-sy); // angle of line
for(var i=0;i<dist;i++) {
// for each point along the line
ctx.fillRect(Math.round(sx + Math.cos(ang)*i), // round for perfect pixels
Math.round(sy + Math.sin(ang)*i), // thus no aliasing
1,1); // fill in one pixel, 1x1
}
}
基本上,您可以找到线条的长度,并逐步遍历该线条,围绕每个位置并填充像素。
用
调用它var context = cv.getContext("2d");
drawLineNoAliasing(context, 20,30,20,50); // line from (20,30) to (20,50)
答案 5 :(得分:2)
如果您需要对画布进行像素级别控制,则可以使用createImageData和putImageData。
HTML:
<canvas id="qrCode" width="200", height="200">
QR Code
</canvas>
和JavaScript:
function setPixel(imageData, pixelData) {
var index = (pixelData.x + pixelData.y * imageData.width) * 4;
imageData.data[index+0] = pixelData.r;
imageData.data[index+1] = pixelData.g;
imageData.data[index+2] = pixelData.b;
imageData.data[index+3] = pixelData.a;
}
element = document.getElementById("qrCode");
c = element.getContext("2d");
pixcelSize = 4;
width = element.width;
height = element.height;
imageData = c.createImageData(width, height);
for (i = 0; i < 1000; i++) {
x = Math.random() * width / pixcelSize | 0; // |0 to Int32
y = Math.random() * height / pixcelSize| 0;
for(j=0;j < pixcelSize; j++){
for(k=0;k < pixcelSize; k++){
setPixel( imageData, {
x: x * pixcelSize + j,
y: y * pixcelSize + k,
r: 0 | 0,
g: 0 | 0,
b: 0 * 256 | 0,
a: 255 // 255 opaque
});
}
}
}
c.putImageData(imageData, 0, 0);
<强> Working sample here 强>
答案 6 :(得分:0)
所以我假设这现在已经不可用了,但是一种解决方法实际上是使用document.body.style.zoom=2.0;
,但是如果您这样做,那么所有画布尺寸都必须除以缩放比例。另外,将变焦设置得更高些以获得更多的锯齿。这是有用的,因为它是可调整的。另外,如果使用这种方法,建议您使功能与ctx.fillRect()
等相同,但要考虑到缩放。例如
function fillRect(x, y, width, height) {
var zoom = document.body.style.zoom;
ctx.fillRect(x/zoom, y/zoom, width/zoom, height/zoom);
}
希望这会有所帮助!
此外,还有一个注解:也可以用于使圆形边缘变尖,以使它们看起来不那么模糊。只需使用诸如0.5的缩放即可!