我可以在HTML <canvas>元素上关闭抗锯齿吗?</canvas>

时间:2008-10-12 09:07:06

标签: javascript html canvas antialiasing

我正在玩<canvas>元素,画线等。

我注意到我的对角线是抗锯齿的。我更喜欢看到我正在做的事情 - 有什么方法可以关闭这个功能吗?

14 个答案:

答案 0 :(得分:58)

1-pixel等坐标上绘制ctx.lineTo(10.5, 10.5)行。在点(10, 10)上绘制一个像素的线条意味着该位置的1像素从9.510.5,这导致两条线在帆布。

如果你有很多单像素线,并不总是需要将0.5添加到你想要绘制的实际坐标上的一个好方法是ctx.translate(0.5, 0.5)你的整个画布在开始。

答案 1 :(得分:47)

对于图片,现在有context.imageSmoothingEnabled = false

然而,没有任何明确控制线条画的东西。您可能需要使用getImageDataputImageData绘制自己的行(the hard way)。

答案 2 :(得分:24)

可以在Mozilla Firefox中完成。将其添加到您的代码中:

contextXYZ.mozImageSmoothingEnabled = false;

在Opera中,它目前是一项功能请求,但希望很快就会添加。

答案 3 :(得分:9)

它必须是抗锯齿矢量图形

抗锯齿是必需,用于正确绘制涉及非整数坐标(0.4,0.4)的矢量图形,这些坐标除了极少数客户外都会这样做。

当给定非整数坐标时,画布有两个选项:

  • Antialias - 根据整数坐标与非整数坐标的距离(圆角误差)绘制坐标周围的像素。
  • Round - 将一些舍入函数应用于非整数坐标(例如,1.4将变为1)。

后一种策略适用于静态图形,但对于小图形(半径为2的圆),曲线将显示清晰的步骤而不是平滑的曲线。

真正的问题是当图形被平移(移动)时 - 一个像素与另一个像素之间的跳跃(1.6 =&gt; 2,1.4 =&gt; 1)意味着形状的原点可能会相对于父容器(不断向上/向下和向左/向右移动1个像素)。

一些提示

提示#1 :您可以通过缩放画布(例如x)来柔化(或硬化)抗锯齿,然后自己将倒数比例(1 / x)应用于几何体(不使用画布) )。

比较(无缩放):

A few rectangles

with(画布比例:0.75;手动比例:1.33):

Same rectangles with softer edges

和(画布比例:1.33;手动比例:0.75):

Same rectangles with darker edges

提示#2 :如果看起来像是一个锯齿状的外观,请尝试几次绘制每个形状(不擦除)。每次绘制时,抗锯齿像素都会变暗。

进行比较。画一次后:

A few paths

画完三次后:

Same paths but darker and no visible antialiasing.

答案 4 :(得分:8)

我会使用自定义线算法绘制所有内容,例如Br​​esenham的线算法。看看这个javascript实现: http://members.chello.at/easyfilter/canvas.html

我认为这肯定会解决你的问题。

答案 5 :(得分:6)

我想补充一点,我在缩小图像尺寸和在画布上绘图时遇到了麻烦,它仍然使用平滑处理,即使它在升级时没有使用。

我用这个解决了:

function setpixelated(context){
    context['imageSmoothingEnabled'] = false;       /* standard */
    context['mozImageSmoothingEnabled'] = false;    /* Firefox */
    context['oImageSmoothingEnabled'] = false;      /* Opera */
    context['webkitImageSmoothingEnabled'] = false; /* Safari */
    context['msImageSmoothingEnabled'] = false;     /* IE */
}

您可以像这样使用此功能:

var canvas = document.getElementById('mycanvas')
setpixelated(canvas.getContext('2d'))

也许这对某人有用。

答案 6 :(得分:5)

ctx.translate(0.5, 0.5);
ctx.lineWidth = .5;

使用这个组合,我可以绘制漂亮的1px细线。

答案 7 :(得分:5)

试试像 canvas { image-rendering: pixelated; } 这样的东西。

如果您只想让一行不被抗锯齿,这可能不起作用。

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

ctx.fillRect(4, 4, 2, 2);
canvas {
  image-rendering: pixelated;
  width: 100px;
  height: 100px; /* Scale 10x */
}
<html>
  <head></head>
  <body>
    <canvas width="10" height="10">Canvas unsupported</canvas>
  </body>
</html>

不过我还没有在很多浏览器上测试过。

答案 8 :(得分:4)

请注意一个非常有限的技巧。如果要创建2色图像,可以在颜色为#000000的背景上使用颜色#010101绘制所需的任何形状。完成后,您可以测试imageData.data []中的每个像素,并设置为0xFF,无论值是不是0x00:

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);

结果将是一个非抗锯齿的黑色&amp;白色图片。这不会是完美的,因为会发生一些抗锯齿,但这种抗锯齿将非常有限,形状的颜色非常像背景的颜色。

答案 9 :(得分:1)

对于那些仍在寻找答案的人。这是我的解决方法。

假设图像为1通道灰色。我只是在ctx.stroke()之后使用了阈值。

ctx.beginPath();
ctx.moveTo(some_x, some_y);
ctx.lineTo(some_x, some_y);
...
ctx.closePath();
ctx.fill();
ctx.stroke();

let image = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height)
for(let x=0; x < ctx.canvas.width; x++) {
  for(let y=0; y < ctx.canvas.height; y++) {
    if(image.data[x*image.height + y] < 128) {
      image.data[x*image.height + y] = 0;
    } else {
      image.data[x*image.height + y] = 255;
    }
  }
}

如果您的图像通道是3或4,则需要修改数组索引,例如

x*image.height*number_channel + y*number_channel + channel

答案 10 :(得分:1)

添加:

image-rendering: pixelated; image-rendering: crisp-edges;

canvas 元素的 style 属性有助于在画布上绘制清晰的像素。通过这篇精彩文章发现:

https://developer.mozilla.org/en-US/docs/Games/Techniques/Crisp_pixel_art_look

答案 11 :(得分:1)

我发现了一种使用上下文的 filter 属性禁用路径/形状渲染抗锯齿的更好方法:

魔法/TL;DR:

ctx = canvas.getContext('2d');

// make canvas context render without antialiasing
ctx.filter = "url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxmaWx0ZXIgaWQ9ImZpbHRlciIgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVDb21wb25lbnRUcmFuc2Zlcj48ZmVGdW5jUiB0eXBlPSJpZGVudGl0eSIvPjxmZUZ1bmNHIHR5cGU9ImlkZW50aXR5Ii8+PGZlRnVuY0IgdHlwZT0iaWRlbnRpdHkiLz48ZmVGdW5jQSB0eXBlPSJkaXNjcmV0ZSIgdGFibGVWYWx1ZXM9IjAgMSIvPjwvZmVDb21wb25lbnRUcmFuc2Zlcj48L2ZpbHRlcj48L3N2Zz4=#filter)";

揭秘:

数据 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>

然后在 url 的最后是对 #filter 的 id 引用:

"url(data:image/svg+...Zz4=#filter)";

SVG 过滤器在 alpha 通道上使用离散变换,渲染时仅在 50% 的边界上选择完全透明或完全不透明。如果需要,可以调整它以添加一些抗锯齿功能,例如:

...
<feFuncA type="discrete" tableValues="0 0 0.25 0.75 1"/>
...

缺点/注意事项/陷阱

注意,我没有用图像测试这个方法,但我可以假设它会影响图像的半透明部分。我也可以猜测它可能不会阻止对不同颜色边界的图像进行抗锯齿。它不是“最接近的颜色”解决方案,而是二元透明度解决方案。它似乎最适合路径/形状渲染,因为 alpha 是唯一使用路径抗锯齿的通道。

此外,使用最小值为 1 的 lineWidth 是安全的。较细的线条变得稀疏或可能经常完全消失。

答案 12 :(得分:0)

关于StashOfCode答案的两个注意事项:

  1. 它仅适用于灰度,不透明的画布(fillRect用白色,然后用黑色绘制,反之亦然)
  2. 当线条较细(〜1px线宽)时,它可能会失败

最好这样做:

描边并填充#FFFFFF,然后执行以下操作:

imageData.data[i] = (imageData.data[i] >> 7) * 0xFF

这可以解决宽度为1px的行。

除此之外,StashOfCode的解决方案是完美的,因为它不需要编写自己的栅格化函数(不仅要考虑线条,而且还应考虑贝塞尔曲线,圆弧,带有孔的填充多边形等)

答案 13 :(得分:0)

这是Bresenham算法在JavaScript中的基本实现。它基于此维基百科文章中描述的整数算术版本:https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm

        // File.Copy(@"‪C:\Users\Asus\Desktop\New.txt", @"D:\New.txt");

        string rootFolder = @"D:\";


        string authorsFile = "Gym.mdf";
        File.Delete(Path.Combine(rootFolder, authorsFile));


        string authorsFile2 = "Gym_log.ldf";
        File.Delete(Path.Combine(rootFolder, authorsFile2));