Hi Damien,

The main problem is that the definition of a stroked path and the definition of a filled path are at odds. If the default stroke width is 1.0 and the default stroke type is "CENTERED", then the stroke is centered on the outline of a path and half of it falls on either side of the outline. For those defaults, if you have the coordinates at pixel centers then integer coordinate fills end up with fuzzy sides (and basic rectangle fills are the most common operation in any system) even though that may help stroked lines and paths. If you have the coordinates at pixel edges then integer fills are nice and crisp and you then only need to adjust for stroked shapes. (Note that on a retina screen with 2x pixels you get both crisp fills and strokes either way, so all hail the new HiDPI world. ;)

For non-AA rendering you actually don't get any fuzziness since only whole pixels are included or not, but you do have the phenomenon of coordinate stability. If you compute an outline and you are off by just a few rounding bits and your coordinates are at the same location as your sampling points then your shape shifts. If the coordinates are halfway between the sampling points then a few bits of rounding will not affect the shape.

Our default is center of pixel sampling, as it is with most rendering systems, so having integer coordinates halfway between them (i.e. at the edges of pixels) makes sense for non-AA.

Java2D has a concept called "stroke control" which applies some rounding process to all coordinates so as to help them end up creating crisper outlines, but it has its drawbacks - particularly in the fact that it fights your ability to have a nice round circle or oval since this concept of shifting points fights the exact geometry involved in the control points of "perfectly round" shapes.

When we were first creating FX we decided that:

- stroke control created some problems that we'd like to avoid even if it does provide some security for new programmers

- the vast majority of control styling was shifting to using concentric filled backgrounds rather than strokes so the fact that default strokes can be fuzzy was a non-issue for the controls team

- we introduced the concepts of inner and outer strokes which play better with outlining controls than the typical graphics library's default of centered strokes and they have similar needs of where integer coordinates should be placed to avoid fuzziness as fills do

- it is time to advance this issue to an exposed one where developers will need to be cognizant of our rasterization rules and stroke geometries to render correctly.

This should be documented better, though.  That much is true...

                        ...jim

On 4/1/15 3:14 AM, Damien Dudouit wrote:
Hello,

I have found the following answer :

http://stackoverflow.com/questions/27846659/how-to-draw-an-1-pixel-line-using-javafx-canvas

*Imagine each pixel as a (small) rectangle (instead of a point). The
integer coordinates are the boundaries between pixels; so a (horizontal or
vertical) line with integer coordinates falls "between pixels". This is
rendered via antialising, approximating half of the line on one pixel and
half on the other. Moving the line 0.5 pixels left or right moves it to the
center of the pixel, getting around the issue.*


I have done quite a bit of custom controls drawing (canvas) with swing and
swt and it's quite a shift of approach that plain coordinates to not match
pixels on display.

In swing/swt, if I want to draw a rectangle from pixel (0,0) to pixel
(2,2), ie. a square of 3x3 pixels I do :
gc.drawRectangle(0, 0, 3, 3); // x, y, width, height

In JavaFX I must do :
gc.strokeRect(0.5, 0.5, 2, 2)

Have a good day,

Damien

2015-04-01 11:42 GMT+02:00 Damien Dudouit <ddudo...@clio.ch>:

Hello,

I'm using a Canvas to display some content (mostly text with lines also
for underline).

I've just noticed something that is a big problem for me : with
line-width=1 and no scaling, actual line-width on display takes 2 pixels.

     Canvas canvas = new Canvas(300, 300);
     GraphicsContext gc = canvas.getGraphicsContext2D();
     gc.setStroke(Color.BLACK);
     gc.setLineWidth(1);
     gc.strokeLine(10, 10, 110, 10);

I'm running Win7 64bits and I have made the test with Oracle jdk8_40 and
jdk7_71 and the result is the same.

That 2 pixel thick line is not perfectly black but dark gray.
If I do 'gc.setLineWidth(2)', then I get a 2 pixel thick line perfectly
black.
If I do 'gc.setLineWidth(0.5)', then I get a 2 pixel thick line with a
lighter gray.

I want to display underline text in the canvas and a 2 pixel thick
underline looks bad.

Any help would be greatly appreciated.

Damien

Reply via email to