This is very annoying. The same thing happens in SVG. It can destroy the image after you have spent so much effort to make everything line up.
Even rounding pixels to the borders of pixels or centers did not help. What I found helped, in the end, add a 0.5-pixel stroke to the fill and compensate for the coordinated 0.5 pixels. Math doesn't make sense, but it all matters.
Below is an example of the problem and the solution I used. Move the mouse over the image to view a larger image and see various artifacts.
One problem remains - the darkening of the joining pixels. This is due to (ALL) browsers using the wrong color model for color mixing. They average the channel with
colorCh = (colorC1 + colorC2) / 2; // incorrect
The color channel values ββare the square root of the output of the display device. The formula used darkens all mixes. (I really want them to fix it). You can see it in the example. The bottom two have adjacent pixels that are too dark.
Right mix
colorCh = sqrt( (pow(colorC1, 2 ) + pow(colorC2, 2)) / 2);
And fix this last small (big problem) problem.
.canC { width:500px; height:400px;} .info { font-size:x-small; }
<div class="info"> Top left drawn normaly at pixel boundaries, with white pixels showing through joins.<br> Top right drawn normaly at pixel centers (offset 0.5,0.5 pixels) bleeds into sourounding pixels.<br> Bottom left drawn with 0.5 pixel stroke at pixel boundaries. Creates a blured (bleeding) edge<br> Bottom right. Drawn with 0.5 pixel stroke and offset by 0.5 pixels. Note that there is no bleeding around the outside and the joins are the best posible. <canvas class="canC" id="canV" width=500 height=400></canvas>
source share