Blo*_*ard 77 html javascript canvas antialiasing
我正在玩<canvas>元素,绘制线条等.
我注意到我的对角线是抗锯齿的.我更喜欢看到我正在做的事情 - 有什么方法可以关闭这个功能吗?
all*_*lan 63
1-pixel在坐标上绘制线条ctx.lineTo(10.5, 10.5).在点上绘制一条像素线(10, 10)意味着1该位置处的该像素到达时9.5会10.5导致在画布上绘制两条线.
0.5如果你有很多单像素线,并不总是需要将你想要绘制的实际坐标添加到一个很好的技巧,一ctx.translate(0.5, 0.5)开始是你的整个画布.
Kor*_*nel 50
对于现在的图像.context.imageSmoothingEnabled= false
但是,没有什么能明确控制线条画.您可能需要使用和绘制自己的线条(艰难的方式).getImageDataputImageData
小智 27
添加这个:
image-rendering: pixelated; image-rendering: crisp-edges;
Run Code Online (Sandbox Code Playgroud)
canvas 元素的 style 属性有助于在画布上绘制清晰的像素。通过这篇很棒的文章发现:
https://developer.mozilla.org/en-US/docs/Games/Techniques/Crisp_pixel_art_look
小智 24
它可以在Mozilla Firefox中完成.将其添加到您的代码中:
contextXYZ.mozImageSmoothingEnabled = false;
Run Code Online (Sandbox Code Playgroud)
在Opera中,它目前是一个功能请求,但希望它很快就会添加.
Cod*_*ith 12
我发现了一种使用上下文filter属性禁用路径/形状渲染上的抗锯齿的更好方法:
ctx = canvas.getContext('2d');
// make canvas context render without antialiasing
ctx.filter = "url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxmaWx0ZXIgaWQ9ImZpbHRlciIgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVDb21wb25lbnRUcmFuc2Zlcj48ZmVGdW5jUiB0eXBlPSJpZGVudGl0eSIvPjxmZUZ1bmNHIHR5cGU9ImlkZW50aXR5Ii8+PGZlRnVuY0IgdHlwZT0iaWRlbnRpdHkiLz48ZmVGdW5jQSB0eXBlPSJkaXNjcmV0ZSIgdGFibGVWYWx1ZXM9IjAgMSIvPjwvZmVDb21wb25lbnRUcmFuc2Zlcj48L2ZpbHRlcj48L3N2Zz4=#filter)";
Run Code Online (Sandbox Code Playgroud)
数据 url 是对包含单个过滤器的 SVG 的引用:
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="filter" x="0" y="0" width="100%" height="100%" color-interpolation-filters="sRGB">
<feComponentTransfer>
<feFuncR type="identity"/>
<feFuncG type="identity"/>
<feFuncB type="identity"/>
<feFuncA type="discrete" tableValues="0 1"/>
</feComponentTransfer>
</filter>
</svg>
Run Code Online (Sandbox Code Playgroud)
然后在 url 的最后是一个 id 引用#filter:
"url(data:image/svg+...Zz4=#filter)";
Run Code Online (Sandbox Code Playgroud)
SVG 滤镜在 Alpha 通道上使用离散变换,在渲染时仅选择 50% 边界上的完全透明或完全不透明。如果需要,可以对此进行调整以添加一些抗锯齿功能,例如:
...
<feFuncA type="discrete" tableValues="0 0 0.25 0.75 1"/>
...
Run Code Online (Sandbox Code Playgroud)
请注意,我没有用图像测试此方法,但我可以假设它会影响图像的半透明部分。我还可以猜测,它可能不会阻止不同颜色边界的图像上的抗锯齿。它不是“最接近的颜色”解决方案,而是二元透明度解决方案。它似乎最适合路径/形状渲染,因为 alpha 是唯一使用路径抗锯齿的通道。
此外,至少使用lineWidth1 个是安全的。较细的线条变得稀疏或经常可能完全消失。
我发现,在 Firefox 中,设置filterdataurl 不能立即/同步工作:dataurl 必须首先“加载”。
例如,以下内容在 Firefox 中不起作用:
ctx.filter = "url(data:image/svg+xml;base64,...#filter)";
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(20,20);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
ctx.filter = "none";
Run Code Online (Sandbox Code Playgroud)
但是等到下一个 JS 框架就可以正常工作了:
ctx.filter = "url(data:image/svg+xml;base64,...#filter)";
setTimeout(() => {
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(20,20);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
ctx.filter = "none";
}, 0);
Run Code Online (Sandbox Code Playgroud)
Izh*_*aki 10
正确绘制涉及非整数坐标(0.4,0.4)的矢量图形需要抗锯齿,所有这些坐标都很少.
当给定非整数坐标时,画布有两个选项:
后一种策略适用于静态图形,但对于小图形(半径为2的圆),曲线将显示清晰的步骤而不是平滑的曲线.
真正的问题是当图形被平移(移动)时 - 一个像素与另一个像素之间的跳跃(1.6 => 2,1.4 => 1)意味着形状的原点可能相对于父容器跳跃(不断变换) 1像素上/下和左/右).
提示#1:您可以通过缩放画布(例如x)来软化(或硬化)抗锯齿,然后自己将倒数比例(1/x)应用于几何(不使用画布).
比较(无缩放):
with(画布比例:0.75;手动比例:1.33):
和(帆布比例:1.33;手动比例:0.75):
提示#2:如果看起来像是一个锯齿状的外观,请尝试几次绘制每个形状(不擦除).每次绘制时,抗锯齿像素都会变暗.
相比.画完一次后:
画完三次后:
我会使用自定义线算法绘制所有内容,例如Bresenham的线算法.看看这个javascript实现:http: //members.chello.at/easyfilter/canvas.html
我认为这肯定会解决你的问题.
虽然我们在 2D 上下文上仍然没有适当的shapeSmoothingEnabled或shapeSmoothingQuality选项(我会提倡这一点,并希望它在不久的将来能够实现),但由于SVGFilters ,我们现在有了近似“无抗锯齿”行为的方法,可以通过其属性应用于上下文.filter。
因此,需要明确的是,它本身不会停用抗锯齿功能,但在实现和性能方面提供了一种廉价的方法(?,它应该是硬件加速的,这应该比 CPU 上的自制 Bresenham 更好))以便在绘制时删除所有半透明像素,但它也可能会创建一些像素斑点,并且可能不会保留原始输入颜色。
为此,我们可以使用<feComponentTransfer>节点来仅抓取完全不透明的像素。
const canvas = document.getElementById("canvas");
const 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
const zoomed = document.getElementById("zoomed");
const zCtx = zoomed.getContext("2d");
zCtx.imageSmoothingEnabled = false;
canvas.onmousemove = function drawToZoommed(e) {
const
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);
}Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
对于那些不喜欢<svg>在 DOM 中附加元素的人,以及生活在不久的将来(或带有实验标志的人),我们正在开发的 CanvasFilter 接口应该允许在没有 DOM 的情况下执行此操作(因此从工人也是):
if (!("CanvasFilter" in globalThis)) {
throw new Error("Not Supported", "Please enable experimental web platform features, or wait a bit");
}
const canvas = document.getElementById("canvas");
const 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 = new CanvasFilter([
{
filter: "componentTransfer",
funcA: {
type: "discrete",
tableValues: [ 0, 1 ]
}
}
]);
// 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
const zoomed = document.getElementById("zoomed");
const zCtx = zoomed.getContext("2d");
zCtx.imageSmoothingEnabled = false;
canvas.onmousemove = function drawToZoommed(e) {
const
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);
};Run Code Online (Sandbox Code Playgroud)
<canvas id="canvas" width="250" height="250" ></canvas>
<canvas id="zoomed" width="250" height="250" ></canvas>Run Code Online (Sandbox Code Playgroud)
或者,您也可以将 SVG 保存为外部文件并将filter属性设置为path/to/svg_file.svg#remove-alpha.
我想补充一点,我在缩小图像和在画布上绘图时遇到了麻烦,它仍然使用平滑,即使它在升级时没有使用.
我用这个解决了:
function setpixelated(context){
context['imageSmoothingEnabled'] = false; /* standard */
context['mozImageSmoothingEnabled'] = false; /* Firefox */
context['oImageSmoothingEnabled'] = false; /* Opera */
context['webkitImageSmoothingEnabled'] = false; /* Safari */
context['msImageSmoothingEnabled'] = false; /* IE */
}
Run Code Online (Sandbox Code Playgroud)
你可以像这样使用这个函数:
var canvas = document.getElementById('mycanvas')
setpixelated(canvas.getContext('2d'))
Run Code Online (Sandbox Code Playgroud)
也许这对某人有用.
小智 5
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5;
Run Code Online (Sandbox Code Playgroud)
有了这个组合,我可以画出漂亮的1px细线.
小智 5
注意一个非常有限的技巧。如果您想创建 2 色图像,您可以在颜色 #000000 的背景上使用颜色 #010101 绘制任何您想要的形状。完成此操作后,您可以测试 imageData.data[] 中的每个像素并将任何不是 0x00 的值设置为 0xFF :
imageData = context2d.getImageData (0, 0, g.width, g.height);
for (i = 0; i != imageData.data.length; i ++) {
if (imageData.data[i] != 0x00)
imageData.data[i] = 0xFF;
}
context2d.putImageData (imageData, 0, 0);
Run Code Online (Sandbox Code Playgroud)
结果将是非抗锯齿的黑白图片。这不会是完美的,因为会发生一些抗锯齿,但是这种抗锯齿将非常有限,形状的颜色非常类似于背景的颜色。
小智 5
尝试类似的东西canvas { image-rendering: pixelated; }。
如果您只想让一行不被抗锯齿,这可能不起作用。
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillRect(4, 4, 2, 2);Run Code Online (Sandbox Code Playgroud)
canvas {
image-rendering: pixelated;
width: 100px;
height: 100px; /* Scale 10x */
}Run Code Online (Sandbox Code Playgroud)
<html>
<head></head>
<body>
<canvas width="10" height="10">Canvas unsupported</canvas>
</body>
</html>Run Code Online (Sandbox Code Playgroud)
不过,我还没有在许多浏览器上测试过。