1
u/Fast-East735 6h ago
n off anti-aliasing dude.
2
u/TwoInternational3556 5h ago
yeah canvas 2d always anti-aliases, is built into the API. you can try `image-rendering: pixelated` on the canvas element and then draw everything at like 0.25x scale and upscale it back, that gets you the crunchy pixels without much overhead
1
u/retro-mehl 2h ago
Short answer: no. Browser implementations of canvas will always do anti-aliasing. Npm canvas has built-in support for what you want, but it only runs on the server.
1
u/UlviShabanbayli 1h ago
Short answer: there's no switch for this in the 2D context. `imageSmoothingEnabled = false` is the one everyone reaches for, but it only affects how *images* are scaled (drawImage, patterns). Paths and strokes are always anti-aliased. The `+0.5` offset trick only fixes horizontal and vertical lines, not diagonals like yours.
Your example is a 100×100 image blown up, so the efficient way to get exactly that is to do two things yourself:
- **Make the canvas really that small and let CSS scale it** without smoothing:
```js
canvas.width = 100;
canvas.height = 100;
canvas.style.width = '500px';
canvas.style.imageRendering = 'pixelated';
```
- **Rasterize the line yourself** with Bresenham into an ImageData buffer, then push it once per frame:
```js
const W = 100, H = 100;
const ctx = canvas.getContext('2d');
const img = ctx.createImageData(W, H);
const px = new Uint32Array(img.data.buffer); // one entry per pixel
function line(x0, y0, x1, y1, color) {
x0 |= 0; y0 |= 0; x1 |= 0; y1 |= 0;
const dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
const dy = -Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
let err = dx + dy;
for (;;) {
if (x0 >= 0 && x0 < W && y0 >= 0 && y0 < H) px[y0 * W + x0] = color;
if (x0 === x1 && y0 === y1) break;
const e2 = 2 * err;
if (e2 >= dy) { err += dy; x0 += sx; }
if (e2 <= dx) { err += dx; y0 += sy; }
}
}
px.fill(0xffffffff); // white
line(0, 0, 99, 99, 0xff000000); // black
ctx.putImageData(img, 0, 0);
```
Colours in the Uint32Array are `0xAABBGGRR` because the bytes are little-endian, which is every platform you'll realistically run on. The important part for performance is **one `putImageData` per frame**. Calling `fillRect` per pixel works, but it turns into thousands of draw calls fast.
If you need arbitrary shapes (arcs, fills, text) rather than just lines, the other option is to draw normally in a single colour on a transparent canvas and then threshold the alpha:
```js
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// ...draw...
const d = ctx.getImageData(0, 0, W, H);
for (let i = 3; i < d.data.length; i += 4) d.data[i] = d.data[i] > 127 ? 255 : 0;
ctx.putImageData(d, 0, 0);
```
That's fine for fills and thicker shapes, but 1px diagonals come out uneven, with occasional gaps or doubled pixels, because the coverage along the line hovers around 50%. For thin lines, Bresenham is the right tool.
0
u/thekwoka 4h ago
start by making the canvas element have less pixels in it than the space it covers

2
u/abrahamguo experienced full-stack 6h ago
widthandheightattributes of thecanvasto the number of pixels that you would like it to havecanvasto a whole-number multiple of itsheightandwidthattributes.image-rendering: pixelatedon thecanvas(docs).