Re: [whatwg] Blurry lines in 2D Canvas
On Fri, Sep 27, 2013 at 2:08 PM, Ian Hickson i...@hixie.ch wrote: On Thu, 5 Sep 2013, Rik Cabanier wrote: On Thu, Sep 5, 2013 at 3:22 PM, Ian Hickson i...@hixie.ch wrote: On Sat, 10 Aug 2013, Rik Cabanier wrote: I was wondering if this is something that happens in Flash as well. It turns out that there's an option called hinting: Keep stroke anchors on full pixels to prevent blurry lines. There's a blog post on what this does: http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html I created an example (in flash sorry) that shows the feature: http://cabanier.github.io/BlendExamples/pixelsnap/pixelsnap.html 2 sets of strokes move across the screen and are also scaled. The top strokes behave like canvas does today. They start of blurry and during the animation they slowly get ticker. For some reason it doesn't look very smooth. The bottom strokes have hinting turned on. They are sharp at the beginning and during the animation they stay the same size until the internal stroke width is large enough. At that point you see a 'jump'. I think canvas should have a similar feature... Can you elaborate on how exactly you would want this to work? How would you avoid the alignment and distortion problems when applying this to anything less trivial than a rectangle? Basically, this would *just* move the control points and the width of paths so the strokes are always aligned to the pixel grid (This would take pixel density and transformations into account). After this, you would draw as usual. Can you define aligned to the pixel grid? If I have a line from x1,y to x2,y, followed by an arc from x2,y back to x1,y with radius r, what should happen and why? Align the anchor points of all the segments. Don't change any of the anti-aliasing behavior. What if they're draw as separate paths? I'm unsure if I follow. That shouldn't make a different. What might be different however, is if you draw a diagonal line in 1 segment or 2 since the middle point will be aligned to the grid in the latter case.
Re: [whatwg] Blurry lines in 2D Canvas
Yeah, this should be specified somewhere. As you point out, luckily everyone is in agreement. On Fri, Sep 27, 2013 at 7:41 PM, Glenn Maynard gl...@zewt.org wrote: On Fri, Sep 27, 2013 at 4:38 PM, Jasper St. Pierre jstpie...@mecheye.net wrote: The issue here is that the canvas API does not specify how pixels are sited on the canvas: if you imagine pixels as enlarged squares on a grid (shush, I know), does an X coordinate of 5 name the center of the square, or the intersection between 4th and 5th squares? That's not the issue this thread is about. I don't know if it's specified (though I suspect is is), but WebKit, Firefox and IE10's Canvas implementations all use OpenGL's coordinate system. This can be seen in the very first post in the thread, which renders consistently in all three browsers. http://jsfiddle.net/V92Gn/128/ -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas
On Thu, 5 Sep 2013, Rik Cabanier wrote: On Thu, Sep 5, 2013 at 3:22 PM, Ian Hickson i...@hixie.ch wrote: On Sat, 10 Aug 2013, Rik Cabanier wrote: I was wondering if this is something that happens in Flash as well. It turns out that there's an option called hinting: Keep stroke anchors on full pixels to prevent blurry lines. There's a blog post on what this does: http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html I created an example (in flash sorry) that shows the feature: http://cabanier.github.io/BlendExamples/pixelsnap/pixelsnap.html 2 sets of strokes move across the screen and are also scaled. The top strokes behave like canvas does today. They start of blurry and during the animation they slowly get ticker. For some reason it doesn't look very smooth. The bottom strokes have hinting turned on. They are sharp at the beginning and during the animation they stay the same size until the internal stroke width is large enough. At that point you see a 'jump'. I think canvas should have a similar feature... Can you elaborate on how exactly you would want this to work? How would you avoid the alignment and distortion problems when applying this to anything less trivial than a rectangle? Basically, this would *just* move the control points and the width of paths so the strokes are always aligned to the pixel grid (This would take pixel density and transformations into account). After this, you would draw as usual. Can you define aligned to the pixel grid? If I have a line from x1,y to x2,y, followed by an arc from x2,y back to x1,y with radius r, what should happen and why? What if they're draw as separate paths? -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
It seems like those should be two separate things instead of lumped all together in a monolithic You can do this if you want... or whatever! Snapping is definitely something different than antialiasing. It's a huge pain for anyone trying to provide a(n accurate) simple 2D primitive library. On 07/23/2013 08:16 PM, Rik Cabanier wrote: I guess there's too many mights in there :-) I want to adjust line positions and line widths to align edges with device pixels but not the user agent might turn off anti-aliasing for all lines and curves On Tue, Jul 23, 2013 at 6:11 PM, Brian Birtles bbirt...@mozilla.com wrote: (2013/07/24 10:07), Rik Cabanier wrote: yeah, at first blush that seemed what was needed. However, this simply turns off antialiasing completely so regular artwork looks terrible. That's a quality of implementation issue. The description of the property value says, Indicates that the user agent shall attempt to emphasize the contrast between clean edges of artwork over rendering speed and geometric precision. To achieve crisp edges, the user agent might turn off anti-aliasing for all lines and curves or possibly just for straight lines which are close to vertical or horizontal. Also, the user agent might adjust line positions and line widths to align edges with device pixels. I'm not sure what use case you have in mind though. Perhaps it's something that doesn't fit that description?
Re: [whatwg] Blurry lines in 2D Canvas
I would just like to note that sometimes we do not WANT to draw precise shapes. :) Many people enjoy the aesthetic of 2d pixel-based graphics, and it should be a viable choice for the graphical style of a game, for instance. Canvas makes this more difficult, and it shouldn't be so! Why can't we have a global option to turn this off if we want to? I'm not trying to advocate for throwing away all antialiasing... I understand that most applications will probably want it by default, and agree with having it as the default. Basically all it is is http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#image-smoothing ... except that we're not talking about scaling. On 09/05/2013 05:22 PM, Ian Hickson wrote: On Tue, 23 Jul 2013, Rik Cabanier wrote: we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ Not always, only if you don't draw the line aligned with the pixel grid (e.g. you draw a diagonal line, or a horizontal or vertical line that isn't centered in the middle of pixels on the pixels grid, or a horizontal or vertical line whose width isn't an integral number of pixels, etc). The options, on a pixel grid display, are: - don't honour the position precisely -- this leads to very ugly artifacts when animating (lines jerk around), and basically means that the graphics aren't accurate. - instead of describing the shapes as vectors, describe them using programs that can adapt to the position and size they're being drawn at, such that they automatically snap to the pixel grid in a pretty fashion -- this is what fonts do. - try to trick the eye by using anti-aliasing when things don't line up exactly on the pixel grid. The first two really aren't plausible options for canvas. On Wed, 24 Jul 2013, Kornel Lesiński wrote: For 1-pixel lines it could be fixed by allowing authors to specify that path should be stroked with lines aligned to inside/outside of the path (which is a useful feature on its own). https://www.w3.org/Bugs/Public/show_bug.cgi?id=22674 On Tue, 23 Jul 2013, Rik Cabanier wrote: Sure, but how can we fix this? What is there to fix? The options above are basically the only options. You can't not do one of them -- there's no way to draw a crisp line that isn't pixel aligned. There's no pixels there. Similarly, there's no way to draw a line that's neither horizontal nor vertical yet is crisp and doesn't look jaggy. The pixels are squares, they don't rotate on modern pixel displays. On Wed, 24 Jul 2013, Kornel Lesiński wrote: Should arc() and bezier curves also be snapped? What if you want a line that touches the curve? That's precisely the problem with snapping -- it is far worse than antialiasing. You can't draw precise shapes if you have snapping. On Wed, 24 Jul 2013, Dirk Schulze wrote: Means implementations would need to take viewport, transformations of the document, transformations on elements in the DOM hierarchy, zoom level, aspect ratio of the canvas, position of the canvas in the document, transformations in the canvas and device pixel resolution into account to snap lines to the correct position on the individual device, right?Otherwise it sounds to be hard to guarantee that you don't see antialiased strokes and lines might snap more then just one device pixel. This would also be a problem for aligning shapes to each other in the canvas I guess. What happens on the next transformation after a drawing operation. Say you draw a line that was snapped to the grid and then you do scale(1.1, 1.1). Shall the implementation redraw the canvas? After all it is an pixel image. A vector based drawing format would be better suited for such a task. Indeed. On Sat, 10 Aug 2013, Rik Cabanier wrote: I was wondering if this is something that happens in Flash as well. It turns out that there's an option called hinting: Keep stroke anchors on full pixels to prevent blurry lines. There's a blog post on what this does: http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html I created an example (in flash sorry) that shows the feature: http://cabanier.github.io/BlendExamples/pixelsnap/pixelsnap.html 2 sets of strokes move across the screen and are also scaled. The top strokes behave like canvas does today. They start of blurry and during the animation they slowly get ticker. For some reason it doesn't look very smooth. The bottom strokes have hinting turned on. They are sharp at the beginning and during the animation they stay the same size until the internal stroke width is large enough. At that point you see a 'jump'. I think canvas should have a similar feature... Can you elaborate on how exactly you would want this to work? How would you avoid the alignment and distortion problems when applying this to anything less trivial
Re: [whatwg] Blurry lines in 2D Canvas
The issue here is that the canvas API does not specify how pixels are sited on the canvas: if you imagine pixels as enlarged squares on a grid (shush, I know), does an X coordinate of 5 name the center of the square, or the intersection between 4th and 5th squares? If we say that it names the center of the square itself, then we'll have sharp strokes but blurry fills -- filling from x=5 to x=10 will only fill half the area in the 5th square. If we say that it names the intersection between the pixels then we'll have blurry strokes but sharp fills. For perspective, old APIs that didn't have support for antialiased graphics like X11 and GDI say that it's the former, but the lack of antialiasing made it not noticeable. Modern APIs like cairo, Quartz 2D and Direct2D say it's the latter, and stick by it. The recommended solution is either to use even line widths with pixel-perfect coordinates or add 0.5 to all lines you draw so they're offset by half a pixel. [0] Neither of these are perfect solutions when you have transforms; perhaps optional support for crisp lines or otherwise turning off AA would be a good idea. But whatever we do, we should certainly pick a pixel citing system (and I'd highly suggest the latter) and make it explicit in the spec. http://cairographics.org/FAQ/#sharp_lines On Fri, Sep 27, 2013 at 5:21 PM, Ruben Rodriguez II wha...@therealcha0s.net wrote: I would just like to note that sometimes we do not WANT to draw precise shapes. :) Many people enjoy the aesthetic of 2d pixel-based graphics, and it should be a viable choice for the graphical style of a game, for instance. Canvas makes this more difficult, and it shouldn't be so! Why can't we have a global option to turn this off if we want to? I'm not trying to advocate for throwing away all antialiasing... I understand that most applications will probably want it by default, and agree with having it as the default. Basically all it is is http://www.whatwg.org/specs/** web-apps/current-work/**multipage/the-canvas-element.** html#image-smoothinghttp://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#image-smoothing... except that we're not talking about scaling. On 09/05/2013 05:22 PM, Ian Hickson wrote: On Tue, 23 Jul 2013, Rik Cabanier wrote: we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ Not always, only if you don't draw the line aligned with the pixel grid (e.g. you draw a diagonal line, or a horizontal or vertical line that isn't centered in the middle of pixels on the pixels grid, or a horizontal or vertical line whose width isn't an integral number of pixels, etc). The options, on a pixel grid display, are: - don't honour the position precisely -- this leads to very ugly artifacts when animating (lines jerk around), and basically means that the graphics aren't accurate. - instead of describing the shapes as vectors, describe them using programs that can adapt to the position and size they're being drawn at, such that they automatically snap to the pixel grid in a pretty fashion -- this is what fonts do. - try to trick the eye by using anti-aliasing when things don't line up exactly on the pixel grid. The first two really aren't plausible options for canvas. On Wed, 24 Jul 2013, Kornel Lesiński wrote: For 1-pixel lines it could be fixed by allowing authors to specify that path should be stroked with lines aligned to inside/outside of the path (which is a useful feature on its own). https://www.w3.org/Bugs/**Public/show_bug.cgi?id=22674https://www.w3.org/Bugs/Public/show_bug.cgi?id=22674 On Tue, 23 Jul 2013, Rik Cabanier wrote: Sure, but how can we fix this? What is there to fix? The options above are basically the only options. You can't not do one of them -- there's no way to draw a crisp line that isn't pixel aligned. There's no pixels there. Similarly, there's no way to draw a line that's neither horizontal nor vertical yet is crisp and doesn't look jaggy. The pixels are squares, they don't rotate on modern pixel displays. On Wed, 24 Jul 2013, Kornel Lesiński wrote: Should arc() and bezier curves also be snapped? What if you want a line that touches the curve? That's precisely the problem with snapping -- it is far worse than antialiasing. You can't draw precise shapes if you have snapping. On Wed, 24 Jul 2013, Dirk Schulze wrote: Means implementations would need to take viewport, transformations of the document, transformations on elements in the DOM hierarchy, zoom level, aspect ratio of the canvas, position of the canvas in the document, transformations in the canvas and device pixel resolution into account to snap lines to the correct position on the individual device, right?Otherwise it sounds to be hard to guarantee that you don't see antialiased strokes and lines might snap more
Re: [whatwg] Blurry lines in 2D Canvas
On Fri, Sep 27, 2013 at 4:38 PM, Jasper St. Pierre jstpie...@mecheye.netwrote: The issue here is that the canvas API does not specify how pixels are sited on the canvas: if you imagine pixels as enlarged squares on a grid (shush, I know), does an X coordinate of 5 name the center of the square, or the intersection between 4th and 5th squares? That's not the issue this thread is about. I don't know if it's specified (though I suspect is is), but WebKit, Firefox and IE10's Canvas implementations all use OpenGL's coordinate system. This can be seen in the very first post in the thread, which renders consistently in all three browsers. http://jsfiddle.net/V92Gn/128/ -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas
On Thu, Sep 5, 2013 at 3:22 PM, Ian Hickson i...@hixie.ch wrote: On Tue, 23 Jul 2013, Rik Cabanier wrote: we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ Not always, only if you don't draw the line aligned with the pixel grid (e.g. you draw a diagonal line, or a horizontal or vertical line that isn't centered in the middle of pixels on the pixels grid, or a horizontal or vertical line whose width isn't an integral number of pixels, etc). The options, on a pixel grid display, are: - don't honour the position precisely -- this leads to very ugly artifacts when animating (lines jerk around), and basically means that the graphics aren't accurate. - instead of describing the shapes as vectors, describe them using programs that can adapt to the position and size they're being drawn at, such that they automatically snap to the pixel grid in a pretty fashion -- this is what fonts do. - try to trick the eye by using anti-aliasing when things don't line up exactly on the pixel grid. The first two really aren't plausible options for canvas. On Wed, 24 Jul 2013, Kornel Lesiński wrote: For 1-pixel lines it could be fixed by allowing authors to specify that path should be stroked with lines aligned to inside/outside of the path (which is a useful feature on its own). https://www.w3.org/Bugs/Public/show_bug.cgi?id=22674 On Tue, 23 Jul 2013, Rik Cabanier wrote: Sure, but how can we fix this? What is there to fix? The options above are basically the only options. You can't not do one of them -- there's no way to draw a crisp line that isn't pixel aligned. There's no pixels there. Similarly, there's no way to draw a line that's neither horizontal nor vertical yet is crisp and doesn't look jaggy. The pixels are squares, they don't rotate on modern pixel displays. On Wed, 24 Jul 2013, Kornel Lesiński wrote: Should arc() and bezier curves also be snapped? What if you want a line that touches the curve? That's precisely the problem with snapping -- it is far worse than antialiasing. You can't draw precise shapes if you have snapping. On Wed, 24 Jul 2013, Dirk Schulze wrote: Means implementations would need to take viewport, transformations of the document, transformations on elements in the DOM hierarchy, zoom level, aspect ratio of the canvas, position of the canvas in the document, transformations in the canvas and device pixel resolution into account to snap lines to the correct position on the individual device, right?Otherwise it sounds to be hard to guarantee that you don't see antialiased strokes and lines might snap more then just one device pixel. This would also be a problem for aligning shapes to each other in the canvas I guess. What happens on the next transformation after a drawing operation. Say you draw a line that was snapped to the grid and then you do scale(1.1, 1.1). Shall the implementation redraw the canvas? After all it is an pixel image. A vector based drawing format would be better suited for such a task. Indeed. On Sat, 10 Aug 2013, Rik Cabanier wrote: I was wondering if this is something that happens in Flash as well. It turns out that there's an option called hinting: Keep stroke anchors on full pixels to prevent blurry lines. There's a blog post on what this does: http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html I created an example (in flash sorry) that shows the feature: http://cabanier.github.io/BlendExamples/pixelsnap/pixelsnap.html 2 sets of strokes move across the screen and are also scaled. The top strokes behave like canvas does today. They start of blurry and during the animation they slowly get ticker. For some reason it doesn't look very smooth. The bottom strokes have hinting turned on. They are sharp at the beginning and during the animation they stay the same size until the internal stroke width is large enough. At that point you see a 'jump'. I think canvas should have a similar feature... Can you elaborate on how exactly you would want this to work? How would you avoid the alignment and distortion problems when applying this to anything less trivial than a rectangle? Basically, this would *just* move the control points and the width of paths so the strokes are always aligned to the pixel grid (This would take pixel density and transformations into account). After this, you would draw as usual.
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Sat, Aug 10, 2013 at 9:43 PM, Rik Cabanier caban...@gmail.com wrote: Ah, so you are relying on pixel snapping (=rounded up to 2 pixels). Rounded to the nearest integer pixel. If you give 1.25, the width would be 1. If you can do that with your approach, why not with strokes that are drawn from the center? It might be possible, in principle, to only snap the border of the stroke instead of the whole thing, but I don't know how to do that or if it'd be worthwhile. It seems like sharp lines are only particularly important for thin strokes (especially 1px), and in those cases the difference between a center and an outer stroke are minor. (I don't know if it's harder to implement, eg. so there's no gap between a fill followed by an outer stroke.) I was wondering if this is something that happens in Flash as well. It turns out that there's an option called hinting: Keep stroke anchors on full pixels to prevent blurry lines. There's a blog post on what this does: http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html I don't know about this, but the description sounds similar to what I'm suggesting. -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Mon, Aug 12, 2013 at 6:45 PM, Glenn Maynard gl...@zewt.org wrote: On Sat, Aug 10, 2013 at 9:43 PM, Rik Cabanier caban...@gmail.com wrote: Ah, so you are relying on pixel snapping (=rounded up to 2 pixels). Rounded to the nearest integer pixel. If you give 1.25, the width would be 1. If you can do that with your approach, why not with strokes that are drawn from the center? It might be possible, in principle, to only snap the border of the stroke instead of the whole thing, but I don't know how to do that or if it'd be worthwhile. It seems like sharp lines are only particularly important for thin strokes (especially 1px), and in those cases the difference between a center and an outer stroke are minor. (I don't know if it's harder to implement, eg. so there's no gap between a fill followed by an outer stroke.) I was wondering if this is something that happens in Flash as well. It turns out that there's an option called hinting: Keep stroke anchors on full pixels to prevent blurry lines. There's a blog post on what this does: http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html I don't know about this, but the description sounds similar to what I'm suggesting. Great! I think we're both on the same page on how the problem can be solved. Do you still believe it's up to the author to do so, or are you leaning towards solving it on the browser side? I would also like to know if people see this as a problem that is worth solving. Many of our Illustrator customers complain about this. We've tried to fix it on the authoring side but it doesn't always work.
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 10:07 PM, Glenn Maynard gl...@zewt.org wrote: On Fri, Aug 9, 2013 at 11:07 PM, Rik Cabanier caban...@gmail.com wrote: How would you fix a 1.5 pixel width for the stroke or a 1.5 transform? By snapping the final, post-transform width of the stroke to an integer. If you scale by 1.25, eg. ctx.scale(1.25, 1.25), then draw a stroke with a lineWidth of 1.5, the resulting width is 1.875 pixels. That would be rounded up to 2 pixels, after applying the transform (scale) and before invoking the trace a path algorithm. Ah, so you are relying on pixel snapping (=rounded up to 2 pixels). If you can do that with your approach, why not with strokes that are drawn from the center? Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). (That seems wrong to me--it should continue to draw based on pixel coverage--but that's a separate issue...) Is it? Obviously you can't draw less than a pixel, but the user did specify that he wants it too look black. strokeStyle = black doesn't mean every pixel in the stroke should be black. It's the color of the pen. If you draw over half of a pixel with a black pen, you get 50% grey. Yes. Does the author want to see the appearance of the 'thin-ness' of the stroke, or is he more interested in the color? I was wondering if this is something that happens in Flash as well. It turns out that there's an option called hinting: Keep stroke anchors on full pixels to prevent blurry lines. There's a blog post on what this does: http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html http://www.kaourantin.net/2005/08/stroke-hinting-in-flash-player-8-aka.html I created an example (in flash sorry) that shows the feature: http://cabanier.github.io/BlendExamples/pixelsnap/pixelsnap.html 2 sets of strokes move across the screen and are also scaled. The top strokes behave like canvas does today. They start of blurry and during the animation they slowly get ticker. For some reason it doesn't look very smooth. The bottom strokes have hinting turned on. They are sharp at the beginning and during the animation they stay the same size until the internal stroke width is large enough. At that point you see a 'jump'. I think canvas should have a similar feature... It'd be one thing if Chrome didn't antialias at all, but if Chrome is antialiasing a stroke with a lineWidth of 1.5, it doesn't make sense that it's not antialiasing a stroke with a lineWidth of 0.75. I don't think this is strictly specified; the only mention of anti-aliasing is an example of how to do it (oversampling). This is tangental, though. Might want to start another thread if you want to go over this more, or we'll derail this one...
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
I think one problem you might run into is that, if you consider a stroked line to be centered on pixel centers rather than pixel edges, then the same path when filled and stroked would touch different pixels along each edge. Consider a 10x10 rectangle, drawn at coordinates coordinates 5, 5. If filled, this would fill pixels 5-14 in X and 5-14 in Y. If stroked, this will draw 1-pixel wide rectangles centered along (5, 5) - (14, 5) - (14, 14) - (5, 5). With antialiasing this will touch pixels 4-15 in each dimension. http://jsfiddle.net/6KS4V/ If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/ . (Please ignore blurriness induced by the CSS upscaling; you can remove the CSS and use a zooming tool if you prefer). Stephen On Tue, Jul 23, 2013 at 7:19 PM, Rik Cabanier caban...@gmail.com wrote: All, we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, but ideally this should never happen. Is this behavior specified somewhere? Is there a way to turn this off?
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 4:17 PM, Stephen White senorbla...@chromium.orgwrote: If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/ My proposal addresses this, by adding an outer stroke mode. http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2013-July/040252.html -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
That's an interesting idea. I suppose the fully general solution would be to have a stroke offset. E.g., with a stroke width of 4 and and offset of 2 you'd get outer, offset -2 you'd get inner, offset 1 you'd get 3 pixels outer and 1 pixel inner, etc. Dunno how useful that is, though. Stephen On Fri, Aug 9, 2013 at 5:24 PM, Glenn Maynard gl...@zewt.org wrote: On Fri, Aug 9, 2013 at 4:17 PM, Stephen White senorbla...@chromium.orgwrote: If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/ My proposal addresses this, by adding an outer stroke mode. http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2013-July/040252.html -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 2:17 PM, Stephen White senorbla...@chromium.orgwrote: I think one problem you might run into is that, if you consider a stroked line to be centered on pixel centers rather than pixel edges, then the same path when filled and stroked would touch different pixels along each edge. Consider a 10x10 rectangle, drawn at coordinates coordinates 5, 5. If filled, this would fill pixels 5-14 in X and 5-14 in Y. If stroked, this will draw 1-pixel wide rectangles centered along (5, 5) - (14, 5) - (14, 14) - (5, 5). With antialiasing this will touch pixels 4-15 in each dimension. http://jsfiddle.net/6KS4V/ If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/. (Please ignore blurriness induced by the CSS upscaling; you can remove the CSS and use a zooming tool if you prefer). Yes, I agree that strokes and fills should be treated the same to avoid this problem. I'm unsure if Glenn's suggestion for an outer and inner stroke fix the problem. An inner or outer stroke will look very different. In addition if the corners of the path don't align with the grid, you will get a blurry outline again. As an experiment, I drew 4 rectangles in JSFiddle with stroke width of .5, .75, 1, 1.5 and 2: http://jsfiddle.net/6KS4V/2/ I aligned them to the grid as Glenn suggested. This is a blown up screenshot from IE (Firefox looked the same): http://bit.ly/16FVCKd and here's one from Chrome: http://bit.ly/19Tf9Ko The rectangle that's 2 points wide is somewhat blurry, but the one that is 1.5 is very bad. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). I then recreated the content in Illustrator, opened the file in Acrobat and took a screenshot: http://bit.ly/15loBhu As you can see, Acrobat doesn't apply any anti-aliasing. It seems to 'snap' the points to the grid and adjust the stroke width so it fills whole pixels. I ran some experiments and I *think* this is also what CSS does. I believe that this could be accomplished with a new attribute in the graphics state. Doing it programmatically should also work but is quite difficult. I wonder if our mozilla friends that work on shumway and pdf.js are running into this...
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 8:16 PM, Rik Cabanier caban...@gmail.com wrote: On Fri, Aug 9, 2013 at 2:17 PM, Stephen White senorbla...@chromium.orgwrote: I think one problem you might run into is that, if you consider a stroked line to be centered on pixel centers rather than pixel edges, then the same path when filled and stroked would touch different pixels along each edge. Consider a 10x10 rectangle, drawn at coordinates coordinates 5, 5. If filled, this would fill pixels 5-14 in X and 5-14 in Y. If stroked, this will draw 1-pixel wide rectangles centered along (5, 5) - (14, 5) - (14, 14) - (5, 5). With antialiasing this will touch pixels 4-15 in each dimension. http://jsfiddle.net/6KS4V/ If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/. (Please ignore blurriness induced by the CSS upscaling; you can remove the CSS and use a zooming tool if you prefer). Yes, I agree that strokes and fills should be treated the same to avoid this problem. I'm unsure if Glenn's suggestion for an outer and inner stroke fix the problem. An inner or outer stroke will look very different. Sure, but it's up to the developer to choose. It looks like Illustrator has something very similar; see the Align Stroke buttons here: http://help.adobe.com/en_US/illustrator/cs/using/WSA1E31D7D-13E6-41ac-AA8C-4AD129B9FC1Ca.html. I don't have a copy of Illustrator to try it, though. In addition if the corners of the path don't align with the grid, you will get a blurry outline again. Well, as long as you choose the right mitering style, I think the corners would be fine. It's basically the same algorithm as normal path stroking, except instead of translating half the stroke width on either side of the path along the tangent, you'd just use the path as one edge and translate the other the full stroke width. As an experiment, I drew 4 rectangles in JSFiddle with stroke width of .5, .75, 1, 1.5 and 2: http://jsfiddle.net/6KS4V/2/ I aligned them to the grid as Glenn suggested. This is a blown up screenshot from IE (Firefox looked the same): http://bit.ly/16FVCKd and here's one from Chrome: http://bit.ly/19Tf9Ko The rectangle that's 2 points wide is somewhat blurry, but the one that is 1.5 is very bad. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). I think this more like what the outer stroke style would do: http://jsfiddle.net/ZrbQh/ The interior rectangle is the same in each one, with the outer edge nudged outwards along the tangent (the sizes may be wrong for the 1 lineWidth cases; I didn't spend too long on it). Stephen I then recreated the content in Illustrator, opened the file in Acrobat and took a screenshot: http://bit.ly/15loBhu As you can see, Acrobat doesn't apply any anti-aliasing. It seems to 'snap' the points to the grid and adjust the stroke width so it fills whole pixels. I ran some experiments and I *think* this is also what CSS does. I believe that this could be accomplished with a new attribute in the graphics state. Doing it programmatically should also work but is quite difficult. I wonder if our mozilla friends that work on shumway and pdf.js are running into this...
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 7:16 PM, Rik Cabanier caban...@gmail.com wrote: In addition if the corners of the path don't align with the grid, you will get a blurry outline again. That's the purpose of the second half of my proposal: snapping coordinates and line widths to integers. As an experiment, I drew 4 rectangles in JSFiddle with stroke width of .5, .75, 1, 1.5 and 2: http://jsfiddle.net/6KS4V/2/ I aligned them to the grid as Glenn suggested. This is a blown up screenshot from IE (Firefox looked the same): http://bit.ly/16FVCKd and here's one from Chrome: http://bit.ly/19Tf9Ko The rectangle that's 2 points wide is somewhat blurry, but the one that is 1.5 is very bad. Right. In case anyone's not following, this is what's happening: https://zewt.org/~glenn/stroke-alignment.png The red box is the rectangle being drawn. The blue lines are the actual strokes. (This was created by hand, it's not an actual Canvas rendering.) The top row is drawing with integer coordinates. With a 1px stroke, the stroke sits across two pixels, so it aliases. With a 2px stroke, it fully covers two pixels and doesn't alias. With a 3px stroke, it aliases again. The middle row is drawing with half-coordinates. The pattern is reversed: clean, aliased, clean. Additionally, fills (with no stroke) always aliases, since the red box lies between pixels. The bottom row is an outer stroke and integer coordinates: neither strokes nor fills alias, in all three cases. This is the mode I'm suggesting. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). (That seems wrong to me--it should continue to draw based on pixel coverage--but that's a separate issue...) -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 8:12 PM, Glenn Maynard gl...@zewt.org wrote: On Fri, Aug 9, 2013 at 7:16 PM, Rik Cabanier caban...@gmail.com wrote: In addition if the corners of the path don't align with the grid, you will get a blurry outline again. That's the purpose of the second half of my proposal: snapping coordinates and line widths to integers. As an experiment, I drew 4 rectangles in JSFiddle with stroke width of .5, .75, 1, 1.5 and 2: http://jsfiddle.net/6KS4V/2/ I aligned them to the grid as Glenn suggested. This is a blown up screenshot from IE (Firefox looked the same): http://bit.ly/16FVCKd and here's one from Chrome: http://bit.ly/19Tf9Ko The rectangle that's 2 points wide is somewhat blurry, but the one that is 1.5 is very bad. Right. In case anyone's not following, this is what's happening: https://zewt.org/~glenn/stroke-alignment.png The red box is the rectangle being drawn. The blue lines are the actual strokes. (This was created by hand, it's not an actual Canvas rendering.) The top row is drawing with integer coordinates. With a 1px stroke, the stroke sits across two pixels, so it aliases. With a 2px stroke, it fully covers two pixels and doesn't alias. With a 3px stroke, it aliases again. The middle row is drawing with half-coordinates. The pattern is reversed: clean, aliased, clean. Additionally, fills (with no stroke) always aliases, since the red box lies between pixels. How would you fix a 1.5 pixel width for the stroke or a 1.5 transform? The bottom row is an outer stroke and integer coordinates: neither strokes nor fills alias, in all three cases. This is the mode I'm suggesting. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). (That seems wrong to me--it should continue to draw based on pixel coverage--but that's a separate issue...) Is it? Obviously you can't draw less than a pixel, but the user did specify that he wants it too look black. I admit that this is not a clear cut problem. Our applications also have different ways of rendering depending on what the user is trying to accomplish. If the intent is to mimic high resolution printed output, we blur the lines like Canvas and SVG currently do. If the screen is considered the output device (like in Acrobat), we snap the line art because it looks better (ie grids for spreadsheets). This is most likely why CSS snaps too.
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 11:07 PM, Rik Cabanier caban...@gmail.com wrote: How would you fix a 1.5 pixel width for the stroke or a 1.5 transform? By snapping the final, post-transform width of the stroke to an integer. If you scale by 1.25, eg. ctx.scale(1.25, 1.25), then draw a stroke with a lineWidth of 1.5, the resulting width is 1.875 pixels. That would be rounded up to 2 pixels, after applying the transform (scale) and before invoking the trace a path algorithm. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). (That seems wrong to me--it should continue to draw based on pixel coverage--but that's a separate issue...) Is it? Obviously you can't draw less than a pixel, but the user did specify that he wants it too look black. strokeStyle = black doesn't mean every pixel in the stroke should be black. It's the color of the pen. If you draw over half of a pixel with a black pen, you get 50% grey. It'd be one thing if Chrome didn't antialias at all, but if Chrome is antialiasing a stroke with a lineWidth of 1.5, it doesn't make sense that it's not antialiasing a stroke with a lineWidth of 0.75. I don't think this is strictly specified; the only mention of anti-aliasing is an example of how to do it (oversampling). This is tangental, though. Might want to start another thread if you want to go over this more, or we'll derail this one... -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Thu, Jul 25, 2013 at 10:29 PM, Rik Cabanier caban...@gmail.com wrote: We're getting a bit off track here :-) We're figuring out an unclear use case. That's as on-track as it gets. :) No, you need to scale, otherwise the content of your canvas won't scale up. For instance, if you have a 100x100 device pixel rect, it has to become a 110x110 device pixel rect if you zoom by 10% Okay, that wasn't clear to me. Pixel ratios are peripheral to what you're describing: you could ask for the same thing any time you're rendering to a dynamically-sized canvas, which simplifies the discussion. I don't know if a complex semi-antialiasing mode is a good approach, though. It'll always have issues (rounded corners won't connect cleanly; it's not clear if it works for fills, or if it works for patterned fills). I don't know if this would work well in practice, or if it's implementable, but here's a two-part approach that might work: - First, add the inner and/or outer stroke modes. This seems useful in and of itself, but the purpose here is to make it so integer coordinates give hard edges, whether or not you have a 1px stroke. - Second, add a mode which causes coordinates to be snapped to integers. This would happen when you make the API call, and be applied after the canvas transform. If you're in scale(1.25), and you call rect(100, 100, 75, 75), it would draw a rect from 100x100 to 194x194, instead of to 193.75x193.75. This would give clean output for rounded edges, since you're adjusting the size of the path as a whole. It would work for fills (which also get aliased edges when transformed). It also works if the fill is a pattern, where turning off antialiasing would make the pattern ugly. -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Thu, Jul 25, 2013 at 12:24 AM, Rik Cabanier caban...@gmail.com wrote: Yes, that's what I had in mind: the developer detects the device pixel ratio and scales up the canvas so the pixels match. That reduces to the simple case, then. The pixel ratio gets out of the picture entirely if you adjust the canvas so it's rendered 1:1 to pixels, so the rules for getting hard edges are the same (half-pixels for strokes, integer pixels for fills). -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Thu, Jul 25, 2013 at 7:05 AM, Glenn Maynard gl...@zewt.org wrote: On Thu, Jul 25, 2013 at 12:24 AM, Rik Cabanier caban...@gmail.com wrote: Yes, that's what I had in mind: the developer detects the device pixel ratio and scales up the canvas so the pixels match. That reduces to the simple case, then. The pixel ratio gets out of the picture entirely if you adjust the canvas so it's rendered 1:1 to pixels, so the rules for getting hard edges are the same (half-pixels for strokes, integer pixels for fills). Unfortunately, no. Let's say you have a device pixel ratio of 1.1 and a canvas of 100x100px. The underlying canvas bitmap should now be created as 110 x 110 pixels and your content should be scaled by 1.1. This will make everything blurry :-(
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On chrome android I see the opposite - the left rests are sharp, the middle ones fuzzy. Sounds like tests needed. On Jul 23, 2013 5:18 PM, David Dailey ddai...@zoominternet.net wrote: Hi Rik, Just affirming what you've said in SVG: http://cs.sru.edu/~ddailey/svg/edgeblurs.svg The middle rects are crisp, having been merely translated leftward and downward by half a pixel. Zooming in from the browser rectifies the problem (as expected) after a single tick. I remember folks discussing sub-pixel antialiasing quite a bit on the SVG lists circa fall/winter 2011. It seemed to cause some troubles for D3. Is that the same issue? Cheers David -Original Message- From: whatwg-boun...@lists.whatwg.org [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Rik Cabanier Sent: Tuesday, July 23, 2013 7:19 PM To: wha...@whatwg.org Subject: [whatwg] Blurry lines in 2D Canvas (and SVG) All, we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, but ideally this should never happen. Is this behavior specified somewhere? Is there a way to turn this off?
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Thu, Jul 25, 2013 at 2:36 PM, Rik Cabanier caban...@gmail.com wrote: On Thu, Jul 25, 2013 at 7:05 AM, Glenn Maynard gl...@zewt.org wrote: On Thu, Jul 25, 2013 at 12:24 AM, Rik Cabanier caban...@gmail.comwrote: Yes, that's what I had in mind: the developer detects the device pixel ratio and scales up the canvas so the pixels match. That reduces to the simple case, then. The pixel ratio gets out of the picture entirely if you adjust the canvas so it's rendered 1:1 to pixels, so the rules for getting hard edges are the same (half-pixels for strokes, integer pixels for fills). Unfortunately, no. Let's say you have a device pixel ratio of 1.1 and a canvas of 100x100px. The underlying canvas bitmap should now be created as 110 x 110 pixels and your content should be scaled by 1.1. This will make everything blurry :-( If you have a pixel ratio of 1.1 (100 CSS pixels = 110 device pixels), and you're displaying in a 100x100 box in CSS pixels, then you create a canvas of 110x110 pixels, so the backing store has the same resolution as the final device pixels. If you don't do that--if you create a 100x100 backing store and then display it in 100x100 CSS pixels--then nothing Canvas can do will prevent it from being blurry, because the backing store is being upscaled by 10% after it's already been drawn. -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Thu, Jul 25, 2013 at 1:28 PM, Glenn Maynard gl...@zewt.org wrote: On Thu, Jul 25, 2013 at 2:36 PM, Rik Cabanier caban...@gmail.com wrote: On Thu, Jul 25, 2013 at 7:05 AM, Glenn Maynard gl...@zewt.org wrote: On Thu, Jul 25, 2013 at 12:24 AM, Rik Cabanier caban...@gmail.comwrote: Yes, that's what I had in mind: the developer detects the device pixel ratio and scales up the canvas so the pixels match. That reduces to the simple case, then. The pixel ratio gets out of the picture entirely if you adjust the canvas so it's rendered 1:1 to pixels, so the rules for getting hard edges are the same (half-pixels for strokes, integer pixels for fills). Unfortunately, no. Let's say you have a device pixel ratio of 1.1 and a canvas of 100x100px. The underlying canvas bitmap should now be created as 110 x 110 pixels and your content should be scaled by 1.1. This will make everything blurry :-( If you have a pixel ratio of 1.1 (100 CSS pixels = 110 device pixels), and you're displaying in a 100x100 box in CSS pixels, then you create a canvas of 110x110 pixels, so the backing store has the same resolution as the final device pixels. You still need the scale though, otherwise the canvas content isn't zoomed (which is what the user requested) If you don't do that--if you create a 100x100 backing store and then display it in 100x100 CSS pixels--then nothing Canvas can do will prevent it from being blurry, because the backing store is being upscaled by 10% after it's already been drawn. Correct. Any scaling to the Canvas bitmap is not something that you can control when you draw the pixels.
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Thu, Jul 25, 2013 at 3:49 PM, Rik Cabanier caban...@gmail.com wrote: You still need the scale though, otherwise the canvas content isn't zoomed (which is what the user requested) (We were talking about device pixel ratios, not zooming--user zooming scales the backing store, which is what we can't do anything about.) I think we're misunderstanding each other, but I'm not sure where. If you're on a 1.1x device, a 100x100 CSS pixel (px) box has 110x100 physical pixels. To draw cleanly into that box, you create a canvas with a 110x110 pixel backing store, and display it in the 100x100px region, eg. canvas width=110 height=110 style=width: 100px; height: 100px; You don't do any scaling within the 2d canvas itself, you just draw to it like a 110x110-pixel canvas. -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Thu, Jul 25, 2013 at 3:59 PM, Glenn Maynard gl...@zewt.org wrote: On Thu, Jul 25, 2013 at 3:49 PM, Rik Cabanier caban...@gmail.com wrote: You still need the scale though, otherwise the canvas content isn't zoomed (which is what the user requested) (We were talking about device pixel ratios, not zooming--user zooming scales the backing store, which is what we can't do anything about.) I think we're misunderstanding each other, but I'm not sure where. If you're on a 1.1x device, a 100x100 CSS pixel (px) box has 110x100 physical pixels. To draw cleanly into that box, you create a canvas with a 110x110 pixel backing store, and display it in the 100x100px region, eg. canvas width=110 height=110 style=width: 100px; height: 100px; You don't do any scaling within the 2d canvas itself, you just draw to it like a 110x110-pixel canvas. We're getting a bit off track here :-) No, you need to scale, otherwise the content of your canvas won't scale up. For instance, if you have a 100x100 device pixel rect, it has to become a 110x110 device pixel rect if you zoom by 10%
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Jul 24, 2013, at 7:19 AM, Rik Cabanier caban...@gmail.com wrote: On Tue, Jul 23, 2013 at 6:20 PM, Glenn Maynard gl...@zewt.org wrote: (The below is about Canvas only; I'm not very familiar with SVG. I think they should be two separate discussions.) Agreed. Sorry to confuse the issue. On Tue, Jul 23, 2013 at 6:19 PM, Rik Cabanier caban...@gmail.com wrote: we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, For Canvas, you should always add 0.5, since you're in the canvas coordinate space, before the pixel ratio is applied. That seemed like an OK idea until I thought about it some more. Doing a .5 scale will also affect your fills so a rect will now have aliased borders. Also adjusting for non-round device pixel ratio or as Kornel mentions, having transforms will still result in blurry lines (unless you do a bunch of math) This is the same coordinate system used by OpenGL and Direct3D 10 (and up), with pixels centered around 0.5x0.5. That is, a pixel sits between 0x0 and 1x1. If you're specifying the center of the line (eg. where the stroke grows outwards from), you need to add a half pixel. (When you're specifying a bounding box, such as drawImage, you don't, since you're at the edge rather than the center of a pixel.) I'm not sure if there's a way to disable antialiasing for paths. Disabling antialiasing to allow people to specify wrong coordinates only seems like it would be more confusing, though. Disabling it is not a solution. The 'crispEdges' option does this and the results look bad. The only solution is to educate people about when and why they need to add a half pixel; even if there was a way to avoid this in general (I'm not sure there is, for an API with Canvas's functionality), it's much too late to change this. I agree that we can't change this, but maybe we can add something to make it better. In PDF there is a feature called strokeAdjust that will make the stroke align to pixel boundaries. Basically, if you turn it on strokeAdjust and the stroke doesn't fill the entire pixel, that pixel isn't drawn. If there's less than a pixel total, you expand the stroke to at least a pixel. Apple has a Core Graphics function called CGGStateSetStrokeAdjust so they would be able to implement this easily. :-) Means implementations would need to take viewport, transformations of the document, transformations on elements in the DOM hierarchy, zoom level, aspect ratio of the canvas, position of the canvas in the document, transformations in the canvas and device pixel resolution into account to snap lines to the correct position on the individual device, right?Otherwise it sounds to be hard to guarantee that you don't see antialiased strokes and lines might snap more then just one device pixel. This would also be a problem for aligning shapes to each other in the canvas I guess. What happens on the next transformation after a drawing operation. Say you draw a line that was snapped to the grid and then you do scale(1.1, 1.1). Shall the implementation redraw the canvas? After all it is an pixel image. A vector based drawing format would be better suited for such a task. Greetings, Dirk
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Wed, Jul 24, 2013 at 6:20 AM, Glenn Maynard gl...@zewt.org wrote: On Tue, Jul 23, 2013 at 11:56 PM, Rik Cabanier caban...@gmail.com wrote: This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, For Canvas, you should always add 0.5, since you're in the canvas coordinate space, before the pixel ratio is applied. That seemed like an OK idea until I thought about it some more. Doing a .5 scale will also affect your fills so a rect will now have aliased borders. I meant you always want to add 0.5 to offsets, not ratio / 2. sorry, that was a typo. I meant to say 'translate(.5, .5)' will offset your fills. On a device with a pixel ratio of 2, you still want to add 0.5, not 1. You want to add 0.5 if you're drawing a 1px stroke, so the rect ends at 0.5 and the stroke extends to the edge of the pixel at 0. If you're drawing a filled rect with no stroke, you don't want to add 0.5, so the rect itself goes to the edge of the pixel rather than the stroke. That is very confusing. So, if there's a scale, you have to unapply the scale to the .5 offset? 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. Also adjusting for non-round device pixel ratio or as Kornel mentions, having transforms will still result in blurry lines (unless you do a bunch of math) 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. I agree that we can't change this, but maybe we can add something to make it better. 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. 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.
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Wed, Jul 24, 2013 at 4:54 PM, Glenn Maynard gl...@zewt.org wrote: On Wed, Jul 24, 2013 at 1:25 PM, Rik Cabanier caban...@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.) Yes, that's what I had in mind: the developer detects the device pixel ratio and scales up the canvas so the pixels match. 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 lines). It's more that the pixel is shrunk but is clamped to at least 1 pixel. I asked our rendering people and it sounds like the feature is implemented quite as described in the book. I'm still trying to find out the details... 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.) Yeah, it's quite complex. 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
[whatwg] Blurry lines in 2D Canvas (and SVG)
All, we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, but ideally this should never happen. Is this behavior specified somewhere? Is there a way to turn this off?
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
Hi Rik, Just affirming what you've said in SVG: http://cs.sru.edu/~ddailey/svg/edgeblurs.svg The middle rects are crisp, having been merely translated leftward and downward by half a pixel. Zooming in from the browser rectifies the problem (as expected) after a single tick. I remember folks discussing sub-pixel antialiasing quite a bit on the SVG lists circa fall/winter 2011. It seemed to cause some troubles for D3. Is that the same issue? Cheers David -Original Message- From: whatwg-boun...@lists.whatwg.org [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Rik Cabanier Sent: Tuesday, July 23, 2013 7:19 PM To: wha...@whatwg.org Subject: [whatwg] Blurry lines in 2D Canvas (and SVG) All, we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, but ideally this should never happen. Is this behavior specified somewhere? Is there a way to turn this off?
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
(2013/07/24 8:19), Rik Cabanier wrote: we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ As discussed with Rik privately, SVG has shape-rendering: crispEdges for this.[1] [1] http://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Wed, 24 Jul 2013 01:18:35 +0100, David Dailey ddai...@zoominternet.net wrote: Just affirming what you've said in SVG: http://cs.sru.edu/~ddailey/svg/edgeblurs.svg The middle rects are crisp, having been merely translated leftward and downward by half a pixel. Zooming in from the browser rectifies the problem (as expected) after a single tick. I remember folks discussing sub-pixel antialiasing quite a bit on the SVG lists circa fall/winter 2011. It seemed to cause some troubles for D3. Is that the same issue? It's not a bug, it's a feature ;) The line is centered around edge of the box. You haven't specified whether you want the line to be outside or inside the box (or overlapping left edge of the box, but not the right, etc.), so you get line in the middle approximated as well as possible. It's not intuitive. It's a pretty common pitfall, but it's logical. For 1-pixel lines it could be fixed by allowing authors to specify that path should be stroked with lines aligned to inside/outside of the path (which is a useful feature on its own). -- regards, Kornel
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
yeah, at first blush that seemed what was needed. However, this simply turns off antialiasing completely so regular artwork looks terrible. On Tue, Jul 23, 2013 at 5:31 PM, Brian Birtles bbirt...@mozilla.com wrote: (2013/07/24 8:19), Rik Cabanier wrote: we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ As discussed with Rik privately, SVG has shape-rendering: crispEdges for this.[1] [1] http://www.w3.org/TR/SVG11/**painting.html#**ShapeRenderingPropertyhttp://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
(2013/07/24 10:07), Rik Cabanier wrote: yeah, at first blush that seemed what was needed. However, this simply turns off antialiasing completely so regular artwork looks terrible. That's a quality of implementation issue. The description of the property value says, Indicates that the user agent shall attempt to emphasize the contrast between clean edges of artwork over rendering speed and geometric precision. To achieve crisp edges, the user agent might turn off anti-aliasing for all lines and curves or possibly just for straight lines which are close to vertical or horizontal. Also, the user agent might adjust line positions and line widths to align edges with device pixels. I'm not sure what use case you have in mind though. Perhaps it's something that doesn't fit that description?
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Tue, Jul 23, 2013 at 5:34 PM, Kornel Lesiński kor...@geekhood.netwrote: On Wed, 24 Jul 2013 01:18:35 +0100, David Dailey ddai...@zoominternet.net wrote: Just affirming what you've said in SVG: http://cs.sru.edu/~ddailey/**svg/edgeblurs.svghttp://cs.sru.edu/~ddailey/svg/edgeblurs.svg The middle rects are crisp, having been merely translated leftward and downward by half a pixel. Zooming in from the browser rectifies the problem (as expected) after a single tick. I remember folks discussing sub-pixel antialiasing quite a bit on the SVG lists circa fall/winter 2011. It seemed to cause some troubles for D3. Is that the same issue? It's not a bug, it's a feature ;) The line is centered around edge of the box. You haven't specified whether you want the line to be outside or inside the box (or overlapping left edge of the box, but not the right, etc.), so you get line in the middle approximated as well as possible. It's not intuitive. It's a pretty common pitfall, but it's logical. For 1-pixel lines it could be fixed by allowing authors to specify that path should be stroked with lines aligned to inside/outside of the path (which is a useful feature on its own). Sure, but how can we fix this? It's not very intuitive that I have to keep track of the devicePixelRatio (and the current CTM?) to get crisp lines. What we need is that artwork 'snaps' to the native pixels while still being antialiased. Illustrator tries to work around this by offering a 'snap to grid' option but users are running into lots of issues (just do a google search for 'illustrator snap to grid')
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
I guess there's too many mights in there :-) I want to adjust line positions and line widths to align edges with device pixels but not the user agent might turn off anti-aliasing for all lines and curves On Tue, Jul 23, 2013 at 6:11 PM, Brian Birtles bbirt...@mozilla.com wrote: (2013/07/24 10:07), Rik Cabanier wrote: yeah, at first blush that seemed what was needed. However, this simply turns off antialiasing completely so regular artwork looks terrible. That's a quality of implementation issue. The description of the property value says, Indicates that the user agent shall attempt to emphasize the contrast between clean edges of artwork over rendering speed and geometric precision. To achieve crisp edges, the user agent might turn off anti-aliasing for all lines and curves or possibly just for straight lines which are close to vertical or horizontal. Also, the user agent might adjust line positions and line widths to align edges with device pixels. I'm not sure what use case you have in mind though. Perhaps it's something that doesn't fit that description?
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
Good memory! I'll dig up that conversation to see what the conclusion was. On Tue, Jul 23, 2013 at 5:18 PM, David Dailey ddai...@zoominternet.netwrote: Hi Rik, Just affirming what you've said in SVG: http://cs.sru.edu/~ddailey/svg/edgeblurs.svg The middle rects are crisp, having been merely translated leftward and downward by half a pixel. Zooming in from the browser rectifies the problem (as expected) after a single tick. I remember folks discussing sub-pixel antialiasing quite a bit on the SVG lists circa fall/winter 2011. It seemed to cause some troubles for D3. Is that the same issue? Cheers David -Original Message- From: whatwg-boun...@lists.whatwg.org [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Rik Cabanier Sent: Tuesday, July 23, 2013 7:19 PM To: wha...@whatwg.org Subject: [whatwg] Blurry lines in 2D Canvas (and SVG) All, we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, but ideally this should never happen. Is this behavior specified somewhere? Is there a way to turn this off?
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
(The below is about Canvas only; I'm not very familiar with SVG. I think they should be two separate discussions.) On Tue, Jul 23, 2013 at 6:19 PM, Rik Cabanier caban...@gmail.com wrote: we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, For Canvas, you should always add 0.5, since you're in the canvas coordinate space, before the pixel ratio is applied. This is the same coordinate system used by OpenGL and Direct3D 10 (and up), with pixels centered around 0.5x0.5. That is, a pixel sits between 0x0 and 1x1. If you're specifying the center of the line (eg. where the stroke grows outwards from), you need to add a half pixel. (When you're specifying a bounding box, such as drawImage, you don't, since you're at the edge rather than the center of a pixel.) I'm not sure if there's a way to disable antialiasing for paths. Disabling antialiasing to allow people to specify wrong coordinates only seems like it would be more confusing, though. The only solution is to educate people about when and why they need to add a half pixel; even if there was a way to avoid this in general (I'm not sure there is, for an API with Canvas's functionality), it's much too late to change this. -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
Seeing what Kornel wrote about a solution to the problem for canvas, makes persuasive support, to me, for Glenn Maynard's argument that [concerning SVG and canvas] I think they should be two separate discussions. One of the intentions (at least historically) of SVG is to allow declarative rather than scripted solutions. As I read this conversation from a declarative perspective (trying to transcode script into markup) I am seeing a dozen little flag-attributes that all interact with one another in a grand logical hyperplane. Sorry, for what might be a flawed metaphor, but I've been stuck in a logical hyperplane for the past few days and I am cursing it! Cheers D (Lie algebra is even worse than Lie geometry! -- https://en.wikipedia.org/wiki/Sophus_Lie ) -Original Message- From: whatwg-boun...@lists.whatwg.org [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Kornel Lesinski Sent: Tuesday, July 23, 2013 10:09 PM To: Rik Cabanier Cc: whatwg@lists.whatwg.org Subject: Re: [whatwg] Blurry lines in 2D Canvas (and SVG) On Wed, 24 Jul 2013 02:13:19 +0100, Rik Cabanier caban...@gmail.com wrote: It's not intuitive. It's a pretty common pitfall, but it's logical. For 1-pixel lines it could be fixed by allowing authors to specify that path should be stroked with lines aligned to inside/outside of the path (which is a useful feature on its own). Sure, but how can we fix this? It's not very intuitive that I have to keep track of the devicePixelRatio (and the current CTM?) to get crisp lines. To what extent does it need to be fixed? Manually snapping lines to canvas pixels isn't too hard, e.g. subtracting 0.5 from x/y and adding 1 to width/height to get pixel-aligned rectangle outside the box. It does get trickier with transforms indeed :( Is it enough to snap to canvas pixels? (future of HD canvas is uncertain, so authors may need to resize canvas to match devicePixelRatio anyway). Is it enough if there was strokeOutside()/strokeInside() that makes untransformed lines pixel-aligned? Or is it necessary to have snapping for odd-width lines that are stroked centered on a path? Do authors expect lines in canvas with non-integer transforms to be crisp? Should arc() and bezier curves also be snapped? What if you want a line that touches the curve? What we need is that artwork 'snaps' to the native pixels while still being antialiased. How should snapping be done? If fill() of a 2x2 rect draws: XX XX how would stroke() look like? .XX. .XX. or .. .. or ... .X. ... If you have path that is 2.5 device pixels wide, is it going to be snapped to different width depending whether you draw it at (0, 0) or (0.1, 0)? Would that also make circles ellipses? Snapping makes animated slow movement choppy, so authors may also want ability to disable it for selected paths/drawing operations or even for each axis separately (e.g. to smoothly animate horizontal movement while object is snapped to pixels vertically, etc.) -- regards, Kornel
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Tue, Jul 23, 2013 at 6:20 PM, Glenn Maynard gl...@zewt.org wrote: (The below is about Canvas only; I'm not very familiar with SVG. I think they should be two separate discussions.) Agreed. Sorry to confuse the issue. On Tue, Jul 23, 2013 at 6:19 PM, Rik Cabanier caban...@gmail.com wrote: we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, For Canvas, you should always add 0.5, since you're in the canvas coordinate space, before the pixel ratio is applied. That seemed like an OK idea until I thought about it some more. Doing a .5 scale will also affect your fills so a rect will now have aliased borders. Also adjusting for non-round device pixel ratio or as Kornel mentions, having transforms will still result in blurry lines (unless you do a bunch of math) This is the same coordinate system used by OpenGL and Direct3D 10 (and up), with pixels centered around 0.5x0.5. That is, a pixel sits between 0x0 and 1x1. If you're specifying the center of the line (eg. where the stroke grows outwards from), you need to add a half pixel. (When you're specifying a bounding box, such as drawImage, you don't, since you're at the edge rather than the center of a pixel.) I'm not sure if there's a way to disable antialiasing for paths. Disabling antialiasing to allow people to specify wrong coordinates only seems like it would be more confusing, though. Disabling it is not a solution. The 'crispEdges' option does this and the results look bad. The only solution is to educate people about when and why they need to add a half pixel; even if there was a way to avoid this in general (I'm not sure there is, for an API with Canvas's functionality), it's much too late to change this. I agree that we can't change this, but maybe we can add something to make it better. In PDF there is a feature called strokeAdjust that will make the stroke align to pixel boundaries. Basically, if you turn it on strokeAdjust and the stroke doesn't fill the entire pixel, that pixel isn't drawn. If there's less than a pixel total, you expand the stroke to at least a pixel. Apple has a Core Graphics function called CGGStateSetStrokeAdjust so they would be able to implement this easily. :-)