I am getting different rendering behavior of a font, "DejaVu Sans Mono", in my Java Swing application if the application loads the font itself vs it being registered with Windows (installed under Windows\Fonts):
Font Rendering Comparison
This difference in behavior is mainly noticeable if Windows display scale preference is at 100%, which is the case on my laptop's 1920x1080 display. Do not get a difference (or at least see any significant difference) when I run the application on a 4K external display with 250% scaling under Windows Display settings.
The font loading code is at the very start of the application, before any Swing/AWT components are created. I am using the Font.createFont() method to load the font using the fontFormat parameter set to Font.TRUETYPE_FONT.
I tried the different values for the awt.useSystemAAFontSettings system property, but the difference is still present, where rendering looks better when the font is installed on Windows vs being loaded via Font.createFont().
Edit: What follows is the utility method in the application that loads the font, where the font file is included in the application's jar file:
public static Font loadResourceFont(
String filename
) {
String pathname = "resources/fonts/" + filename;
java.io.InputStream in = null;
try {
in = AppUIFonts.class.getResourceAsStream(pathname);
if (in == null) {
log.error("Unable to find resource \""+pathname+"\"");
return null;
}
return Font.createFont(Font.TRUETYPE_FONT, in);
} catch (Exception e) {
log.error("Unable to load font \""+filename+"\": "+
e.getLocalizedMessage(), e);
} finally {
IOUtil.closeQuietly(in);
}
return null;
}
Edit: The font rendering difference is only observed when using smaller font sizes. In the screenshot above, the font size is 13. Not sure what the exact threshold is, but I think font sizes at 16 or larger do not exhibit the rendering problem.
Edit: Based on information provided by @gthanop, enabling debug font logging of the JVM, I see the difference in options set on the font when it is loaded by the application vs registered with the operating system. The following is when the font is loaded by app (ignore the size value as I did the log capture when using 4k display at 250% scaling, so effective size is quite large):
INFO: Strike for ** TrueType Font: Family=DejaVu Sans Mono Name=DejaVu Sans Mono style=0 fileName=C:\tmp\+~JF2835760196081226032.tmp at size = 35 use natives = false useJavaRasteriser = true AAHint = 4 Has Embedded bitmaps = false
The following is when font is registered/installed to the system:
INFO: Strike for ** TrueType Font: Family=DejaVu Sans Mono Name=DejaVu Sans Mono style=0 fileName=C:\Users\user\AppData\Local\Microsoft\Windows\Fonts\DejaVuSansMono.ttf at size = 35 use natives = true useJavaRasteriser = false AAHint = 4 Has Embedded bitmaps = false
Notice the difference in the use natives option and the useJavaRasteriser option. Not sure if possible to change these options at the application code level as it appears these options are controlled by internal Java classes.
createFont(instead of descriptions), as well as what file path you give tocreateFont.PLAINstyle indeed. Tried to look at internals a bit of where the font is constructed when calling the constuctor and didn't manage to find out what's wrong (there are several internal classes involved and a registration process which reads fonts from JRE and Windows system directory). Tried to load the font (downloaded from your link) withcreateFontas well as the corresponding font in Windows system directory and these two have the same behaviour, but are different from the constructor's font, despite also evaluating as equal.equals(for all 3 fonts). Also tried setting variousRenderingHintswhile custom painting some text with these fonts, but the problem remains. As an aside, I usedSystem.setProperty("sun.java2d.debugfonts", "true");which enables logging for internal font implementing classes (using Oracle's JRE) and helped a bit, so it may be useful to take a look at this as a bird's eye view of what's going on internally. There should exist better methods to look into it than digging internals though. I can't look further into all of this for the time being, sorry.