How to Turn Off Antialiasing on an HTML ≪Canvas≫ Element

Can I turn off antialiasing on an HTML canvas element?

For images there's now context.imageSmoothingEnabled= false.

However, there's nothing that explicitly controls line drawing. You may need to draw your own lines (the hard way) using getImageData and putImageData.

HTML5 Canvas and Anti-aliasing

Anti-aliasing cannot be turned on or off, and is controlled by the browser.

Can I turn off antialiasing on an HTML <canvas> element?

How to avoid antialiasing effect in HTML5 Canvas

You can add support for line-width relative to zoom (just make sure restore() is applied after stroke or all settings will return before anything is drawn):

var lineWidth = 1;                       // line width

function draw() {
context.save();
context.beginPath();
context.scale(zoom, zoom);
context.lineWidth = zoom * lineWidth; // line-width * zoom
context.moveTo(100, 50);
context.lineTo(100, 100);
context.stroke();
context.restore(); // restore last
}

Modified fiddle

If you want to keep about 1 pixel regardless of scale you can invert the line-width formula:

  context.lineWidth = 1 / (zoom * lineWidth);

Result

However, there will be small rounding errors affecting the anti-aliasing processing on some scales.

Solution

The only real way to avoid this issue is to manually apply a matrix to points representing the line, make the values integers, then render the result of those as a line using the Bresenham or, IMO, the better and faster EFLA algorithm and via ImageData, pixel-by-pixel, and finally push that to the bitmap. You can wrap all this into a single function of course.

This also mean you need to track the matrix. In newer browsers you can use currentTransform and soon getTransform() to obtain current transformation, or you can use a custom matrix solution for cross-browser and backward compatibility (there are many out there, here is mine).

There is currently no way to turn off anti-aliasing for vectors rasterized to the canvas.

Demo

I didn't implement boundary checks in this quick demo, but that is something you need to implement as well so the lines doesn't wrap around (ie. only draw if x >= 0 && x < width etc. .. per pixel).

window.onload = function() {  var canvas = document.getElementById('c');var context = canvas.getContext('2d');var matrix = new Matrix();var zoom = 1.0;
function clear() { context.clearRect(0, 0, canvas.width, canvas.height);}
function draw() { matrix.reset(); // replaces save/restore matrix.scale(zoom, zoom);
// manually draw line via matrix and EFLA line(context, 100, 50, 100, 100);}
// custom line functionfunction line(context, x1, y1, x2, y2) {
// instead of transforming context, apply matrix to points: var p1 = matrix.applyToPoint(x1, y1); var p2 = matrix.applyToPoint(x2, y2);
// create a bitmap (for demo), or obtain an existing one (getImageData) var idata = context.createImageData(canvas.width, canvas.height); var data32 = new Uint32Array(idata.data.buffer); _line(data32, p1.x|0, p1.y|0, p2.x|0, p2.y|0, canvas.width); context.putImageData(idata, 0, 0);}
// EFLA line algorithmfunction _line(data, x1, y1, x2, y2, w) {
var dlt, mul, sl = y2 - y1, ll = x2 - x1, yl = false, lls = ll >> 31, sls = sl >> 31, i;
if ((sl ^ sls) - sls > (ll ^ lls) - lls) { sl ^= ll; ll ^= sl; sl ^= ll; yl = true }
dlt = ll < 0 ? -1 : 1; mul = (ll === 0) ? sl : sl / ll;
if (yl) { x1 += 0.5; for (i = 0; i !== ll; i += dlt) setPixel(data, (x1 + i * mul)|0, y1 + i, w) } else { y1 += 0.5; for (i = 0; i !== ll; i += dlt) setPixel(data, x1 + i, (y1 + i * mul)|0, w) }}
// Set a pixel (black for demo)function setPixel(data, x, y, w) {data[y * w + x] = 0xff000000}
$('#c').mousewheel(function(e) { e.preventDefault(); if (e.originalEvent.deltaY < 0) { zoom *= 1.1; } else { zoom /= 1.1; } clear(); draw();});

draw(); };
body {overflow:hidden}
<script src="//code.jquery.com/jquery-3.1.1.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js"></script><script src="//cdn.rawgit.com/epistemex/transformation-matrix-js/master/matrix.min.js"></script>
<canvas id="c" width="800" height="600"></canvas>

HTML5 canvas disable antialias on primitive (curves, ...)

The imageSmoothingEnabledonly affects images drawn to canvas using drawImage() (hence the name imageSmoothingEnabled). There is sadly no way to disable this for lines and shapes.

As with 6502's answer and previous answers on SO you will need to implement "low-level" methods to achieve this.

Here are some links to some common algorithms for various primitives:

  • Bresenham line algorithm (see this answer for implementation)
  • Midpoint circle algorithm (and ellipse with the same) Here's an implementation.
  • Bezier curve (implementation at CodeProject)

The way you need to implement this is to get the x and y coordinates from these formulas. Then you need to either to use rect(x, y, 1, 1) or set a pixel directly by altering the image data buffer directly. The latter tend to be faster for these sort of things.

In both cases you will have a relatively huge performance reduction as you need to iterate using JavaScript versus browser's internal compiled iteration.

Is turning off antialiasing for HTML Canvas still not possible?

Short answer: Still not possible.

Here's part of the working group's old discussion of the matter.

For now, if you just want images to not be anti-aliased you can always draw them on whole pixels.

Dynamically turn on/off antialiasing and shadows in WebGLRenderer

You can't enable/diable antialiasing from a WebGL context after creation. The only way is to create a new context and submit all the buffers and textures again.

So, ideally you would only need to create a new WebGLRenderer with the antialias boolean. This doesn't work yet thought, but I'm working to have it working ASAP.



Related Topics



Leave a reply



Submit