[whatwg] Blurry lines in 2D Canvas (and SVG)

Glenn Maynard glenn at zewt.org
Wed Jul 24 16:54:53 PDT 2013

On Wed, Jul 24, 2013 at 1:25 PM, Rik Cabanier <cabanier at gmail.com> wrote:

> sorry, that was a typo. I meant to say 'translate(.5, .5)' will offset
> your fills.

(All I meant in the first place was that the pixel ratio isn't a factor
here.  Maybe it's SVG that needs the ratio-dependent adjustment.)

> That is very confusing. So, if there's a scale, you have to unapply the
> scale to the .5 offset?

If there's a scale, the width of the stroke is going to be scaled too.  In
that case, you either have to do adjustments across the board (no
translation is going to make a 0.9-pixel stroke fill a pixel), or you need
to do something like disabling antialiasing.

>  I agree this isn't all that obvious.  What if there was an option for
>> strokes to align themselves to the inside or outside of the path, instead
>> of centering over the path?  That way, drawing 5x5-10x10 would cause both
>> the stroke and the edge of the fill to be pixel-aligned.  This is
>> Photoshop's "Position" stroke option, which can be set to "inside",
>> "outside" or "center".  I don't know if that makes sense with the way paths
>> work, and it would make the stroke's path dependent on its width.
> That's a cool feature, but doesn't solve the problem. Users would still
> need to be aware that they need to align to whole pixels to stroke.

It solves the problem that it's a bit of a pain to have to supply
edge-aligned coordinates when you're filling and centered coordinates when
you're using a 1px stroke.  It eliminates the need to do any half-pixel
offsetting at all in a lot of cases.

> Do you mean Canvas transforms or higher-level transforms, like CSS
>> scaling?  I don't think Canvas can help with the latter.
> Canvas transforms. I agree the resampling or transforming the canvas
> bitmap after the fact is not something we can control.
>> Non-integer pixel ratios lead to all kinds of aliasing and quality
>> problems.  I suspect trying to fix them is futile...
> A lot of people have zoom turned on and there are quite a few devices that
> have non-integer pixel ratios. I'd like to solve the problem everywhere if
> possible.

If zoom is on, then that's the above: a compositing-stage transform that
happens after rendering, which Canvas probably can't help with.

If you have a non-integer pixel ratio, and no "HD" canvas backing store (it
sounds like those may be getting dropped), then that seems like the same
issue: the canvas will be rescaled at compositing time and there's nothing
Canvas itself can do to prevent blurriness.  (The developer could still
work around it by hand, by using a higher-resolution Canvas so the backing
store doesn't actually get resized at compositing time.  They'll need to do
this anyway, or everything will be blurry, not just strokes.)

> In PDF there is a feature called "strokeAdjust" that will make the stroke
>>> align to pixel boundaries. I've attached a drawing that shows the feature.
>>> Basically, if you turn it on and the stroke doesn't fill the entire pixel,
>>> that pixel isn't drawn.
>>> Apple has a Core Graphics function called "CGGStateSetStrokeAdjust" so
>>> at least they would be able to implement this easily. :-)
>> Isn't this simply disabling antialiasing?  That's what the illustration
>> seems to show.
> It tells the renderer not to use over-scan but center-scan for strokes. I
> was under the impression that GPU have centerscan by default and that
> implementors have to add a bunch of code to work around this.

I don't follow the terminology, but from your image and description ("If
there's less than a pixel total, you expand the stroke to at least a
pixel", that sounds like disabling antialiasing (maybe only for certain

 That'll work in certain cases, with the caveats that have been mentioned:
>> you don't want it when animating lines, for diagonals, if you have rounded
>> corners, etc.
> I *think* we still alias in certain cases. I will check.

You could get more complex and turn off antialiasing for lines that aren't
exactly vertical or horizontal.  I suspect that would cause odd issues; for
example, seams at the boundary between a horizontal line and a rounded
edge, or a rounded edge being dimmer than the hard edges it connects.  (I
also don't know enough about paths and their implementations to know how
feasible this is.)

It sounds complex and with its own problems, and the only case where it
might help is if you want to draw hard lines after calling
canvas.scale(0.9, 0.9), which seems uncommon to me.  In all typical cases,
being able to set strokes to inside or outside seem to handle the rest (if
that's something that fits in Canvas's path design; I don't know the

Glenn Maynard

More information about the whatwg mailing list