I noticed that some of the canvas2d methods seem to have a feature that was surprising to me. In particular, the context.lineTo(x, y) and context.drawImg(imgObj, x, y) methods. I would have thought the x,y coordinates would be taken only in integers, but something special seems to happen if I give them as a float – the browser seems to magically adjust the color of the pixels on the edges of the graphical components to paint them “in between” the 2 discrete neighboring pixels coordinates.
For example, lets say my stroke color is black, and then I call context.lineTo(100.2, 0). I’ll get a nice black line the goes to x coordinate 100, but the pixel at coordinate 101 is also painted, but it’s painted a shade of grey that seems to correspond with the fractional part of the x coordinate(eg a darker grey for context.lineTo(100.4, 0))
I made a jsfiddle demo
where I animate both images and lines to demonstrate the effect visually. In both cases, the lower image and lower line were animated by passing floating point arguments to the canvas methods – and you can see how they’re very smooth due the browser doing its magic. The line effect is difficult to see at high monitor resolutions, but it’s there. The image is impressive because it doesn’t just blend the edges, it seems to be fully aware of transparency.
opera, firefox, and chrome all seem to do it.
My questions:
Is this documented in any browsers/spec?
Is there a term for this?
I want to call this some form of anti-aliasing or interpolation, but I don’t think either of these terms are correct for this. I want know what it’s called.
As most canvas systems, the one of HTML5 is based on float coordinates. And rounded coordinates are between screen pixels.
This means that aliasing has to occur, in order to better fit pixels you put over more than one “real pixel”.
This is a very important thing to know, as it lead to fuzzier and wider lines, depending on the position of the line. On the following picture, both lines have a
lineWidthof 1 but the first one is drawed aty=1while the second one is drawed aty=4.5:See this post I wrote on this problem where I give 2 functions I made as an example of a way to deal with it (I use similar functions for rectangles too). More generally, you have to take into account the line width but the logic should be clear using the picture : to have sharp shapes, try to fill the real screen pixels.
Drawing images at not integer coordinates smooths the image, which is rarely the desired effect, and also brings a performance penalty, as interpolation has to occur. You generally should draw your images, when they’re at screen scale, only on rounded coordinates, both for performances and for fidelity to original.