I\'m wondering if anyone knows if it\'s possible to enable sub-pixel rendering in an HTML5 canvas in Chrome (and/or Safari).
Chrome does sub-pixel rendering in HTML,
Here's a way of doing sub-pixel rendering for any canvas content (text, images, vectors, etc). http://johnvalentine.co.uk/subpixel-html5-canvas.htm.
Outline of the method
It draws onto a canvas, which is then drawn to the screen to take advantage of RGB-striped subpixels. It works with alpha channels too. Note that this might not work if you are using a portrait display, non-striped pixels, or if your browser displays canvases at a lower resolution than your display.
There's scope for fine-tuning, but it's a big gain for a simple method. It works on all browsers I've tested, but only where canvas-to-screen pixel ratio is 1:1 (but I believe solutions have been offered for that).
Short answer: No. Not possible
This is one of two topics that frustrates a lot of Canvas users.
Subpixel rendering/anti-aliasing of any kind is up to the browser. This means that different browsers are prone to render things in different ways.
A lot of people have asked for anti-aliasing to be an option that can be turned on or off for a specific context. No luck of anything like that yet.
Chrome in particular you'll need to keep an eye on, because the way they have handled sub-pixel rendering has changed drastically over the past 4 months. If you start using the Chrome developer channel you'll get a preview of the things they keep trying out. They've been doing quite a bit of testing in this area, and have even pushed some drastic regressive changes that I've complained about.
The takeaway here is that:
It is possible, depending on the platform. Here is how to do it:
canvas.getContext('2d', {alpha: false})
-webkit-font-smoothing
property to the value you want: auto
, antialias
(blur), subpixel-antialias
("LCD" text with color fringe) or none
.This will apply to all of the text in the canvas.
Here's a screenshot from Chrome 81 on Mac; the text in the green rectangle is canvas fillText
:
Here is the source of this file:
<!DOCTYPE html>
<style>
canvas {
border: 1px solid green;
}
div {
position: float;
float: left;
}
#a {
-webkit-font-smoothing: auto;
}
#b {
-webkit-font-smoothing: antialiased;
}
#c {
-webkit-font-smoothing: subpixel-antialiased;
}
#d {
-webkit-font-smoothing: none;
}
</style>
<div id="a">
(auto)<br>
??????????<br>
||||||||||<br>
IIIIIIIIII<br>
llllllllll<br>
//////////<br>
</div>
<div id="b">
(antialiased)<br>
??????????<br>
||||||||||<br>
IIIIIIIIII<br>
llllllllll<br>
//////////<br>
</div>
<div id="c">
(subpixel)<br>
??????????<br>
||||||||||<br>
IIIIIIIIII<br>
llllllllll<br>
//////////<br>
</div>
<div id="d">
(none)<br>
??????????<br>
||||||||||<br>
IIIIIIIIII<br>
llllllllll<br>
//////////<br>
</div>
<script>
'use strict';
function add(container) {
let canvas = document.createElement('canvas');
const width = container.clientWidth;
canvas.style.width = `${width}px`;
const height = 40;
canvas.style.height = `${height}px`;
canvas.width = Math.floor(width * window.devicePixelRatio);
canvas.height = Math.floor(height * window.devicePixelRatio);
container.append(canvas);
let ctx = canvas.getContext('2d', {alpha: false});
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'black';
ctx.font = '12pt Arial';
ctx.fillText('\/!|hello world', 0, height / 2);
}
add(a);
add(b);
add(c);
add(d);
</script>
I don't believe this is possible presently.
It's a hard problem because canvas provides so much low-level control to the user. If canvas starts doing intelligent things like this, it may break some other functionality the user was expecting.
Consider the subpixel rendering for other graphical elements - depending on the application, the programmer may not want that, and you certainly wouldn't want subpixel rendering turned on arbitrarily for the whole element as an all-or-nothing proposition. Imagine getting the color of a specific pixel - what's the right answer here? Should canvas lie and return the expected color, or return the actual color (so we have to answer questions all day here on SO about "why is this pixel I made black being measured as dark red?").
There are some who would argue that Firefox is doing the wrong thing here.