How to set the DPI of Java Swing apps on Windows/Linux? - java

If you have an monitor with a DPI over 150 (such as Macbook Pro), you may also find the problem: the font on the Java Swing app is too small for high DPI monitor, and I cannot change the font size at all ( It ignores the Windows DPI directly, only displaying the very original DPI-->96 ). I can do nothing but changing the screen resolution, which could absolutely make everything blurry on LCD.
Yes, I have a laptop with a high DPI monitor, 15.6' with 1920x1080 resolution, some Java desktop apps look very small on my laptop, such as Matlab, Burpsuite etc. I have been searching the Internet for a very very long time, but still cannot find a method for the problem. I know I can change the JRE fonts through JRE_HOME/lib/font/fontconfig.properties.src, but I cannot find any place to set the default font size or DPI for Java desktop fonts.
Does the problem have no solution? Do you have a high DPI monitor? How do you do with such apps? Does Swing give up high DPI users?

I'm currently investigating this issue on Windows. Here's what I found:
Most Swing Look & Feels don't support high DPI at all, not even Nimbus even though it's supposed to be scalable. I found some old blog posts saying that Nimbus might eventually offer high DPI scaling, but apparently that never happened.
The one exception is System LAF but its default font is ~10% smaller than the actual system font size, at all DPI settings. Moreover, System must be selected explicitly as described here:
http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
There's no single scaling factor that you could set in Swing, either. The specific LAF has to provide code to handle scaling. So the best you can do is select System and hope it's good enough.
However, JavaFX does correctly and automatically scale all the way up to 150% on my system. If at all possible, I suggest you use JavaFX to build your GUI.
edit: I made a couple small test programs and took comparison screenshots for various GUI frameworks, Swing themes, and DPI settings. This might be informative for people reading this question: http://kynosarges.org/GuiDpiScaling.html

Short answer: You need to run it on JRE 9+.
Long answer:
This is because the Java runtime declared itself to be "DPI-aware" but didn't really supported it for AWT and Swing. Java applications were sized and rendered based on pixels rather than being properly scaled, this included HiDPI displays.
Anyways, this has been recently solved.
See the issue JEP 263: HiDPI Graphics on Windows and Linux
and the upgrade.
So, increasing the font size does not work (because it does not increase the rest of the things); the jvm argument -Dsun.java2d.dpiaware=false does not work (because it is not really supported); and the manifest file + registry edit (for Windows) just does not work.
Solution: You need to run it on JRE 9+ because it really supports this feature.

This answer solved the issue on my 4K-screen Ubuntu laptop.
In the application's config file, I added the -Dsun.java2d.uiScale=2.5 Java parameter and now, upon executing, the application is scaled well and is usable.

It appears that on Linux (Gtk) you can work around this by scaling the Apps DPI using the following before starting the app.
export GDK_SCALE=2
(You can also reduce you monitor resolution but that's no solution at all).

On Linux, it doesn't seem possible to do scaling with any Swing look and feel, according to my experiments. However, it is possible to do it using a hack involving VNC, vncdesk. Here is my configuration for running gradle --gui under vncdesk:
.vncdesk/1/settings.ini:
[desktop]
width = 1050
height = 650
[window]
title = gradle
name = gradle in vncdesk
class = GradleInVncdesk
scale_factor = 2
.vncdesk/1/startup:
#!/bin/sh
cd "$INVOCATION_DIR"
matchbox-window-manager&
exec gradle --gui "$#"

I managed to solve it following these instructions: Link.
It's in German, but I will translate the important stuff.
Create this registry-key:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide]
"PreferExternalManifest"=dword:00000001
Create a manifest file with this content:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*">
</assemblyIdentity>
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="amd64" publicKeyToken="1fc8b3b9a1e18e3b">
</assemblyIdentity>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<ms_windowsSettings:dpiAware xmlns:ms_windowsSettings="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</ms_windowsSettings:dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
Copy it into the bin directory where the java.exe and javaw.exe is inside and named it java.exe.manifest and javaw.exe.manifest (You will have two files with the same content but different names).
HTH.
Bernd

As #demented hedgehog said setting the GDK_SCALE=2 environment variable does work under Linux.
If you are using JetBrains IntelliJ you can set Enviroment variables just for your project under Edit configurations > Build and Run > Enviroment variables
You can see below where to put the GDK_SCALE=2.

Related

Create java program / export as jar without any dpi scaling?

Is it possible to turn off dpi scaling in my program/export it as non dpi scaling support? I have made a program using swt windowbuilder with eclipse, and it gets messed up on different dpi resolutions.
Is the only way to go about this to use something like MigLayout?
If so, can anyone point me on how to use that?
The program gets messed up with different dpi settings (and text scaling)
I haven't found anything very helpful in this subject, other than people giving advice on how to make the program dpi scale able. (which i do not need in this case, and would prefer it just be disabled if possible)

JavaFX 8 HiDPI Support

I just tried out the JavaFX Hello World Example on a 4k screen on Arch Linux, but unfortunately the GUI does not scale.
The documentation says
Hi-DPI support. JavaFX 8 now supports Hi-DPI displays.
So how can I make my application dpi aware?
Hi-DPI support on various devices
For OS X Macs with retina display it should "just work" - JavaFX is aware of Hi-DPI Macs and will scale the UI appropriately. If you set the spacing in a VBox to 8, then that is a device independent unit; on a non-retina display mac it will take up 8 pixels, on a retina display which has double the resolution, the spacing will take up 16 pixels. Because the retina display also has twice the DPI as well as twice the resolution of the non-retina display, the physical screen measurement of the space will be the same regardless of device.
For Windows and Linux devices, your results may be less satisfactory as JavaFX 8u20 does not currently by default work out arbitrary DPI resolutions on such devices and scale to them appropriately. What you could do is perform most of your measurements in css as em units (which are based on the point size of the scene's root's default font) and similarly for fxml, and then set the point size of the scene root's default font appropriately depending on what you determine from querying the screen's DPI resolution. See the discussion in this answer for further information and sample code: javafx automatic resizing and button padding.
Specific to Gnome
Gnome 3 has a setting for the scaling factor which can be controlled by this command:
gsettings set org.gnome.desktop.interface scaling-factor 2
You can query this scaling factor by reading the user's gnome profile settings and use this in conjunction with querying the screen DPI to work out how an appropriate scaling factor then apply the scaling using the techniques described above.
Just a personal anecdote - when I tried using Gnome 3 scaling (CentOS 7 and also a recent Fedora release) on a Hi-DPI display a couple of days back, I found the overall support for Hi-DPI across applications running under Linux to be pretty spotty. Certainly, the support was much improved from CentOS 6 when I attempted that, but there was still quite a way to go to achieve quality Hi-DPI support across windowing toolkit, standard apps and third party apps. For this reason, I believe that running HiDPI Gnome desktops is still quite a bleeding edge thing which is definitely not for everyone - I am sure that this situation will change over time.
Bitmapped Images
From a JavaFX team lead blog entry on Hi-DPI:
In Apple’s applications (starting with the iPhone and iPad with their retina displays), the solution to the problem is for the application developer to supply two images instead of one for each image asset. For example, the splash screen will be supplied with two images, one at normal resolution and one at 2x the resolution. The files are named the same but the 2x one is named according to some convention, such that at runtime the platform will lookup the 2x version on retina behind the scenes. In such a way, your application says “fooImage.png” but “fooImage#2x.png” is looked up instead when on a machine with a retina display.
I do not know whether this bitmapped image choosing functionality for Hi-DPI displays is currently in Java 8u20 or not - you might have to implement it yourself by querying the screen with screen.getDpi(), then loading the appropriate bitmap.
4K Devices
4K is a lot of pixels to push. JavaFX will by default use hardware a accelerated graphics pipeline when such a graphics pipeline is available. Some graphics hardware may not be fully optimized for 4K display (e.g. not enough video ram), which might lead to an application which either does not work or performs poorly. I also don't believe that currently a lot of effort has gone into investigating JavaFX performance on various 4K devices - it might "just work", but it might not either. You will need to test your application on the target hardware to determine the current capabilities of JavaFX applications when running on that hardware. You might also need to tweak the application according to some of the suggestions above.
A user has reported an issue with JavaFX 8u20 when attempting to display a 4K video using JavaFX:
JavaFX Ultra HD (4K) video
Background
Supporting Hi-DPI under OS X was (likely) simpler than Windows/Linux devices as the target devices are either retina or non-retina display with one being an exact 2x scale of the other and direct support from the OS X system can be leveraged to help achieve the retina scaling. With Windows/Linux, probably what is required is an ability to scale at factors other than just 2x, and that is covered by the (currently outstanding and scheduled) feature request RT-32521 Support global coordinate scaling with DPI-based default. Scaling by an integral amount usually gives the best visible results.
Additional Resources
Kynosarges discussion of JavaFX DPI Scaling.
The JavaFX team load wrote a blog on JavaFX on retina Macs (this is a little dated now, as JavaFX now supports retina Macs).
Randahl's perspective on JavaFX: Designing for Multiple Resolutions.
Apple have some nice advice on optimizing applications for high resolution devices, it's not JavaFX specific and some of the advice does not apply to JavaFX, but there are still some useful general principals and techniques there.
A complete guide to coding for Hi-DPI devices is outside the scope of this particular answer - you can google various web resources to get more information.
If you have further questions on Hi-DPI support for JavaFX, I suggest you ask them on the openjfx-dev JavaFX developer mailing list.
Wiki Answer
This answer may have some possible inconsistencies or errors and may date over time. I have made the answer community wiki. If you are aware of specific corrections, device and OS limitations or support model support for Hi-DPI on JavaFX, please feel free to edit this answer or move it to the OpenJFX wiki (where it probably belongs anyway).
I faced the same problem. I built javaFX application in my surface pro 3, which did not scale but the fxml apps did. then I installed jre8u221 withiout replacing the updated version it suggested. It fixed the problem

inconsolata and netbeans

When I installed inconsolata everything looked fine, however when I tried viewing it on netbeans it look like this:
I tried using both the ttf and otf versions and they both looked messed up.
Is this a java issue? Win 7 64 bit issue? Is there any way to fix this?
You could try disabling font antialiasing in NetBeans.
Open up your netbeans.conf
As part of the netbeans_default_options section add -J-Dswing.aatext=false -J-Dawt.useSystemAAFontSettings=off.
Edit: fvu also provided a helpful link to a relevant section in the NetBeans font rendering FAQ.
If you want to play around with NetBeans font rendering settings, take a look at http://wiki.netbeans.org/FaqFontRendering
Unfortunately, what this article concludes is that default font rendering settings provide the best possible experience. At least under Windows. I have tried all the possibilities with Inconsolata and defaults provide the the best look indeed.
As a workaround, you can try two things:
Decrease contrast of your color scheme, i.e. by decreasing lightness of a background and/or increasing lightness of your font. It makes font rendering issues less visible.
Use NegativeScreen: http://arcanesanctum.net/negativescreen/
You may find your experience improved, but this is up to your personal preference.
It's not just NetBeans, although it is probably not simply the Inconsolata font's fault either. There seems to be a problem at the level of the underlying Java system that NetBeans is built on. I say this because the exact same problem shows up in the IDEs created by Jetbrains -- IntelliJ IDEA, WebStorm, PyCharm, and possibly others.

Java 6 Hardware Acceleration on Mac OS X

I have a java application I wrote that loads up a TTF font and uses the drawString method from Graphics2D. This gets called every 50ms with the x and y positions changing each time to make the text move. When I run the program on Windows, I get 0-1% CPU usage, but on Mac I get about 75% usage. This Windows machine does have a better CPU but there's no way there should be that big of a difference. I think it has to do with Hardware Acceleration and I want to know how enable it. I found some Mac specific Java properties, but none of them lowered my CPU usage. Any ideas how to increase Java 2D performance on OS X? Thanks.
EDIT1: I thought that these properties would help but they didn't.
System.setProperty("sun.java2d.opengl", "true");
System.setProperty("apple.awt.graphics.UseQuartz","true"); System.setProperty("apple.awt.graphics.EnableQ2DX","true");
EDIT2: You can download the project source and byte code here: http://drop.io/ExampleScreenSaver
EDIT3: Since drop.io no longer exists, I uploaded the project to Google Code. Now you can browse the code without downloading it. I still have no idea how to approach this problem so any help would be appreciated.
Run the profiler in "jvisualvm" to identify where the time goes.
Apple JVM font handling is specific to MacOS X. For instance, if a glyph is not found for a character in the current font, the JVM looks for another font to display the character. Also, antialiasing is enabled by default (you should check that you have it enabled on Windows if you want to compare).
I am not surprised Apple's implementation is using more CPU.
OpenGL can be enabled when calling java e.g.
java -Dsun.java2d.opengl=true MyJavaGame
Too enable opengl from inside your java application
System.setProperty("sun.java2d.opengl", "true");
Not sure how this pans out on the iOS / Linux / Android and may require more looking into.

How to get Java swing application to respect OS DPI settings

Is there a way to set DPI in Swing? For the whole application? And if there is, how do I set it to the value of the system DPI?
I guess there must be a way to do it, as I mentioned this feature must have benn added to NetBeans in some of latest versions...
Thank you for reading.
I think it would depend on the Look and Feel you're using.
As far as I know Substance LAF honors the current desktop DPI settings.
Here is some related info https://pushingpixels.dev.java.net/files/documents/7463/95862/dpi-bof.pdf

Categories

Resources