3
votes

I try to display 1px thin lines in an Android app, but the FMX framework behaves strange: Lines are often drawn a little bit blurred, which can be seen on the screen. Even on a high resolution screens (tested on a Ascend Mate 7, which has a FullHD 1080x1920 on a 16 inch display) it is noticeable. It doesn't matter if I use a component, like a TLine or TRectangle (without sides - just Height=1) or if I draw a line myself on a canvas (e. g. with Canvas.Stroke.Thickness := 1.0 and Canvas.DrawLine()). Compiling as a Windows application shows 1px lines correctly, but on Android the lines are drawn as 2px or sometimes as 3px. Sometimes something between it, like one solid line and a second half transparent line.

It is also strange, that drawn line thickness seems to change when scrolling the view (at runtime) which contains the lines. Setting the thickness below the value 1.0 allows drawing lines really as 1px, but then the lines themself become transparent. No matter what I try - I cannot create a solid 1px thin completely opaque black line. And the above problems (e. g. while scrolling) still persists. Changing TForm.Quality does not help either. Native Android apps do not seem to have problems drawing thin lines.

Here is a native screenshots (zoom in to measure line thickness):

enter image description here

I tried some suggestions, like "moving" the lines: http://sourceoddity.com/blog/2013/10/using-tcanvas-in-delphi-for-android/. This helps a little bit with removing the bluring, but the lines are still drawn with more than 1px and I would like to solve the problem in one place (I cannot rewrite / redraw all of the hundreds of components in the framework).

Here is the sample project from the screenshot above: https://www.dropbox.com/s/le70jf601axd1xf/example.zip?dl=1

I tested this with version 10.1 (Berlin), but this strange behaviour occured in previous versions too (as long as I remember).

1
This question/answer speaks about 1 px wide dotted line, but I recall it is the same for 1 px wide solid lines, offsetting the line ends with 0.5 px leads to a rendering of truly 1 px wide horizontal and vertical lines.Tom Brunberg
I tried this approach already (the link to the blog in my text above). It helps removing the blur, but there is still the scaling problem. I start to realize, that firemonkey seems to apply the scaling of the Android system. On my Huawei Ascend Mate 7, I have in the display settings the option to change view mode (scaling): small, middle (default), big. GetWindowScale() of TPlatformServices.Current.GetPlatformService(IFMXWindowService) as IFMXWindowService gives me following values: 2.5 (small), 2.75 (middle), 3 (big). I might be wrong with that, but I think that could be the problem...StanE
...which means that the problem resides deeper in the FMX framework. It makes sense to scale the app based on the scaling of the system. But if every device has a different scaling and especially uses fractions, then I think I understand why this could happen. Could the FMX framework have a problem with rendering / antialiasing, if it uses scales like 2.75 to scale the entire app? Is it possible to disable scaling (if it is really the problem)?StanE

1 Answers

0
votes

On android, you must take several think in account. First their is real pixel and virtual pixel (real pixel = virtual pixel x scale). this mean that when you ask to draw a 1px line on a XXhdpi device (with scale = 3) then you will have a 3px line that will be drawed. of course this not result in blured line, except if scale is for example 1.5

Second thing, connected to the first, if it's you don't start to draw you line on a real pixel. on android pos is a single, so you can draw you line everywhere, even on the middle of a real pixel. in this way of course the system will start to blur the line to draw it from the middle of one pixel to the middle of another pixel (because can't draw only half of a pixel). for avoid this always use Canvas alignToPixel function.

the other think you need to take care in account is that the firemonkey framework use an ugly designed parameter: form.quality. when you setup it to highquality the opengl used be firemonkey will be setuped to antialisased everything (including simple line), resulting in blur. to remove it you can setup it to normal, but in this way round corner / circle will be absolutely ugly on device with scale ratio of 1.

the option i personnally choose is to stay on form.quality = low (no anti aliased) and draw everything (including line, rectangle, etc) myself using the android api. You can take a look at this svn: https://svn.code.sf.net/p/alcinoe/code/ or if you want to see directly load in android this demo : https://svn.code.sf.net/p/alcinoe/code/demos/ALFmxControls/Android/Release/ALFmxControls/bin/ALFmxControls.apk