Closed wolfgang-ch closed 2 months ago
Just wondering as you already have a BufferedImage, why not use that? I always found AWTs Graphics2D to provide superior features and quality over SWT GC.
Just wondering as you already have a BufferedImage, why not use that? I always found AWTs Graphics2D to provide superior features and quality over SWT GC.
In https://github.com/mytourbook/mytourbook/issues/1376#issuecomment-2200085788 a BufferedImage is used but the AWT/SWT scaling issue is visible to me since I have a 4k display, 2 weeks ago.
I need to use autoScale > 100 otherwise the UI is too small on a 4k display
FYI, I have 3 4k monitors, each with a difference scale because each is a different physical size. I personally find that letting the system do the scaling looks better than what the application tries to do, so I change this settings on the java.exe and the javaw.exe:
@merks With you suggestion, the scaling is different, SWT looks worse compared with AWT, e.g. large S, but it is blury
This screenshot is zoomed 300% without antialiasing
In my case, my primary monitor is at 100% and then the others are 125% and 225%, so I think in that case the two smaller monitors are down scaling the full resolution of the primary monitor, and that looks quite nice visually. The captures here though look blurry but that's not how it actually look on the smaller monitors because these images all physically the same size across the monitors:
Anyway, it's just a thought because the behavior without this setting was horribly tiny unreadable content for me.
In any case,, there are folks working hard to improve the hdpi support, but I doubt AWT will be a priority for them. Have you been testing with the 4.33 I-Builds? You might consider helping in the hdpi effort. If so, I expect some folks could probably offer some guidance.
I just tested it with I20240818-1800 but it looks not better.
The improved HiDPI support (for Windows) is still work in progress and will not be available in the upcoming 2024-09 release in an "easy" way. If you want to test, you can add the following VM arguments to your Eclipse application:
-Dswt.autoScale.updateOnRuntime=true -Dswt.autoScale=quarter
.
As a result, each shell will rescale depending on the monitor is currently placed on.
We plan to provide an Eclipse preference to enable the feature as soon as possible in 2024-12 development (early M1 phase), so that it becomes easier to activate and test that feature.
In any case,, there are folks working hard to improve the hdpi support, but I doubt AWT will be a priority for them.
We have not taken a detailed look into AWT by now. But since we are using AWT in our RCP product as well, we will consider that at some point in time in more detail. But of course, any help on this is appreciated, so if you/someone wants to work on improvements in the meantime, feel free :-)
I've tested the above code with -Dswt.autoScale.updateOnRuntime=true -Dswt.autoScale=quarter
and eclipse I20240818-1800 on my 2 Monitors
The shell is opened in the first monitor (my Notebook) and it looks OK...
...when moving the window to the second monitor, then SWT has the same scaling issue as AWT (you have to zoomin into the image to skip github scaling)
This is the slightly adjusted code SWTvsAWT_FontsAndImages.zip
I took a deeper look into your example and hope I understand it correctly: if am not mistaken, the reason for your issue is that the images you create are raster-scaled, i.e., they are drawn according to a 100% monitor scaling and then the result is simply scaled up pixel-by-pixel. Thus, it's not a rendering problem but a rescaling problem.
Precisely, you always seem to reder with fixed font sizes into an image of fixed size while your widgets become larger with autoScale > 100 (e.g., the values passed to shell.setSize()
are automatically scaled up). The gc.drawImage()
operation will also do an automatic scale-up, and since the image is provided as a bitmap and not via some image data provider that could provide the image in a proper scaling, it will just use a raster scaling, which leads to blurry results. The SWT one works for the scaling of the primary monitor, because an SWT image is always properly initialized for the primary monitor's zoom. But that's SWT functionality and not done by AWT, which is why AWT results look worse.
I see two options for you:
-Dswt.autoScale=false
@HeikoKlare
Thank you for your analysis
-Dswt.autoScale=false/100
is not an option for me otherwise the app UI fonts/icons on a 4k display are too tiny
In my app, the texts are painted into an image because this is done in a background thread which may explain why this is not rendered directly (without an image) in the UI thread. This "background" image is then overlayed and rendered in the UI thread.
... and not via some image data provider that could provide the image in a proper scaling, ...
Which image data provider do you mean ?
Doing the rendering in a background thread is, of course, fine. You then just have to consider the proper size for the image to be rendered. Currently, you render the image for a 100% scaling in the background and then it is used to draw it onto a potentially higher-scaled UI, which means it is upscaled when drawing the image onto the GC.
What you need to do is to consider the current scaling when creating the image you paint into (in your background thred). An easy (non-API) way to do so would be to retrieve the zoom value via DPIUtil.getNativeZoom()
and use that to scale the image and font you are drawing into (the scale factor should be DPIUtil.getNativeZoom() / 100
. That will only work as long as the application only has a single zoom value and the operating system keeps tracks of (blurry) scaling it when moving to another monitor with a different scaling (as explained by Ed).
A probably better option (and one that will also work when having the updateOnRuntime
feature enabled for better HiDPI support) would be to implement an ImageDataProvider
(org.eclipse.swt.graphics.ImageDataProvider
), which only has a single method getImageData (int zoom)
. In that implementation you can create your image with the zoom passed to the method of the provider on demand. You can, of course, still cache the buffered image for a specific zoom value inside, but this way you will be able to receive the zoom value and create a properly sized image for that. You can pass this image data provider to the constructor of the image to be draw via the GC in the UI. When painting that image in the UI, the image data provider will be requested to deliver the image with the proper zoom. You will probably need to run your application with -Dswt.autoScale=quarter
then, as otherwise this zoom value will only be 100 or 200.
This sounds interresting, I'll try it by using the ImageDataProvider
solution
This sounds interresting, I'll try it by using the
ImageDataProvider
solution
Of course that makes rendering in the background somewhat uselsess as it will ask that ad-hoc if required, I must confess that I still don't understand why not rendering it directly on the image?!
@HeikoKlare 🏆 🥇 🥈 🥉
It works 😎
In this test, SWT is not yet using an ImageDataProvider
but AWT
This is the modified code with an ImageDataProvider
SWTvsAWT_FontsAndImages.zip
Thank you for the feedback, @wolfgang-ch! Great to see that it works and also an interesting insight for us to see the interaction with AWT.
Describe the bug
Mainly small fonts are looking really bad compared with SWT fonts.
Why do I use AWT fonts? SWT has a limit with antialiasing when drawing into an image, see here https://github.com/mytourbook/mytourbook/issues/1376#issuecomment-2200085788
With autoScale=100 (for none 4k displays) the AWT font rendering is as good as SWT but autoScale > 100 has this issue.
Is there any AWT/SWT parameter to disable AWT font/image scaling when swt.autoScale > 100 ?
To Reproduce
Expected behavior AWT within SWT should scale fonts with the same quality as SWT
Screenshots This screenshot should be viewed without github scaling !
Environment:
Select the platform(s) on which the behavior is seen:
Additional OS info (e.g. OS version, Linux Desktop, etc) Windows 10
JRE/JDK version java.vendor.version=Temurin-21.0.4+7
Version since 4.23 and older
Workaround (or) Additional context Have not yet found