Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using anti-aliasing for text universally? #218

Closed
teras opened this issue Nov 27, 2020 · 13 comments
Closed

Using anti-aliasing for text universally? #218

teras opened this issue Nov 27, 2020 · 13 comments
Milestone

Comments

@teras
Copy link

teras commented Nov 27, 2020

Based on the comment here #152, I was wondering if there's a global UI parameter to use anti-aliasing everywhere. I have FlatLaf side by side with IntelliJ, and then FlatLaf looks less "modern" because of lack of anti-aliasing.

Should I inherit some UI classes instead? And if yes, again, is it possible to have it somewhere centrally, not for every single instance?

(I know I could fork and do whatever change I like, but I think this might be interesting for other people too, that's why I ask).

@DevCharly
Copy link
Collaborator

Hmm, actually FlatLaf uses anti-aliasing everywhere for painting border, icons, etc.
For text rendering the rendering hints provided by Java are used to enable anti-aliased text rendering.

Where exactly do you see non-anti-aliased rendering?
Can you post a screenshot?

@teras
Copy link
Author

teras commented Nov 28, 2020

Sure.
I am talking about text anti-aliasing, I'm going to correct the title.
I tried this actually and I was expecting to work, but it didn't (I am using Java 14, but also tried with Java 9 and 15).

UIManager.getLookAndFeel().getDefaults().put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

Here's a screenshot:
screenshot

@teras teras changed the title Using anti-aliasing universally? Using anti-aliasing for text universally? Nov 28, 2020
@DevCharly
Copy link
Collaborator

Strange...

I'll try to reproduce the issue.
What Linux distro and version do you use?
Who is the vendor of the Java versions you use? (OpenJDK, AdoptOpenJDK, ...)

Could you set a breakpoint at following line and post content of desktopHints?
Then debug step into the ifs and check whether line 554 is executed.

Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS );
if( desktopHints instanceof Map ) {
@SuppressWarnings( "unchecked" )
Map<Object, Object> hints = (Map<Object, Object>) desktopHints;
Object aaHint = hints.get( RenderingHints.KEY_TEXT_ANTIALIASING );
if( aaHint != null &&
aaHint != RenderingHints.VALUE_TEXT_ANTIALIAS_OFF &&
aaHint != RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT )
{
defaults.put( RenderingHints.KEY_TEXT_ANTIALIASING, aaHint );
defaults.put( RenderingHints.KEY_TEXT_LCD_CONTRAST,
hints.get( RenderingHints.KEY_TEXT_LCD_CONTRAST ) );
}
}

You could also try whether following command line option enables AA for your app: -Dawt.useSystemAAFontSettings=on
https://docs.oracle.com/javase/8/docs/technotes/guides/2d/flags.html#aaFonts

@DevCharly
Copy link
Collaborator

BTW does text anti-aliasing work in your app if you use another Laf? E.g. Metal, Nimbus, ...

@teras
Copy link
Author

teras commented Nov 29, 2020

I have created this small & simple test program

package visuals;

import com.formdev.flatlaf.FlatLightLaf;
import javax.swing.*;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import java.awt.*;

public class Main {
    public static void main(String[] args) throws UnsupportedLookAndFeelException {
//        LookAndFeel laf = new NimbusLookAndFeel();
        LookAndFeel laf = new FlatLightLaf();
        UIManager.setLookAndFeel(laf);
        laf.getDefaults().put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        
        JFrame frame = new JFrame("Test Window");
        JPanel content = new JPanel(new BorderLayout());
        content.add(new JLabel("Hello"), BorderLayout.CENTER);
        frame.setContentPane(content);
        frame.pack();
        frame.setVisible(true);
    }
}

When I use Flat LaF then anti-aliasing doesn't work.
When using Nimbus, it does, and I can really control it with the property setting.
When using the command line argument, it also works with Flat LaF.

Linux Arch
JDK AdoptOpenJDK 15.0.1.hs-adpt installed through sdkman!
But also tried with version 11.0.9.hs-adpt and also java.net version 9.0.4-open

Then I tried putting a breakpoint.
Indeed after setting the value, the code goes near the line you mentioned.
But at line 535 the object it retrieves is a "Nonantialiased text mode" SunHints$Value

Although I am not a UI expert, it seems to me that, when requesting defaults, you always put some defaults there and apply the (non) anti-alias (line 412). So when I later on apply the anti-alias setting, this is never read and of course ignored.
What happens with Nimbus is that it caches the defaults, so when I set them, they are persistent and next time a drawing operation is performed, it properly works.

@DevCharly
Copy link
Collaborator

The problem in the example code is that you invoke LookAndFeel.getDefaults(). You should not do that because in most look and feels this method creates a new instance of the defaults hash table, which is not used by the active Laf. The one exception is Nimbus, which always returns the same instance. See also Javadoc of LookAndFeel.getDefaults(): https://github.com/openjdk/jdk/blob/8d432d29b88571c1bbca4b625e308d4a6cc07577/src/java.desktop/share/classes/javax/swing/LookAndFeel.java#L707-L710

Instead simply use UIManager.put(...), which is used by all look and feels.
Or if you want set it only for the active Laf, then use UIManager.getLookAndFeelDefaults().put(...).

So the remaining question is why is anti-aliasing disabled by default on your system?
I'll install Arch Linux soon to try this out...

I have some Linux distros here (e.g. Ubuntu and Fedora) where anti-aliasing is enabled by default...

@teras
Copy link
Author

teras commented Nov 29, 2020

I can confirm that this works!

I am using KDE Plasma, maybe that's why?

Anyway I consider the problem solved and sorry for bugging you 😄

@DanielLyi
Copy link

Helped me too

@DevCharly
Copy link
Collaborator

@teras and @DanielLyi there is now a fix in main branch that enables text anti-aliasing on Linux even if no Gnome or KDE Desktop properties are available

@DevCharly DevCharly added this to the 1.2 milestone May 4, 2021
@HiddenMachine3
Copy link

HiddenMachine3 commented Nov 4, 2022

@DevCharly
Hey I tried the solutions mentioned here, and none of them seem to work for icons
Here is the code I am using to test this:

import com.formdev.flatlaf.FlatDarculaLaf;
import jiconfont.icons.font_awesome.FontAwesome;
import jiconfont.swing.IconFontSwing;

import javax.swing.*;
import java.awt.*;

public class Main {
    public static void main(String[] args) throws UnsupportedLookAndFeelException {
//        LookAndFeel laf = new NimbusLookAndFeel();
        LookAndFeel laf = new FlatDarculaLaf();
        UIManager.setLookAndFeel(laf);
        UIManager.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        UIManager.put("useSystemAAFontSettings", "on");
        UIManager.put("swing.aatext", "true");
        System.setProperty("awt.useSystemAAFontSettings","on");
        System.setProperty("swing.aatext", "true");
        UIManager.getDefaults().put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        IconFontSwing.register(FontAwesome.getIconFont());

        JFrame frame = new JFrame("Test Window");
        JPanel content = new JPanel(new BorderLayout());

        JButton button = new JButton("Hello");
        button.setPreferredSize(new Dimension(100, 50));
        button.setIcon(IconFontSwing.buildIcon(FontAwesome.ARROW_LEFT, 40));
        content.add(button, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(content);
        frame.pack();
        frame.setVisible(true);
    }
}

This doesn't seem to work on Windows 10. I am using Jiconfont to create the icons from FontAwesome

This is the result I am getting, where the anti aliasing is not working on the icons:
image
image

Edit: This issue seems to be present regardless of the LookAndFeel, but please help me out,

@HiddenMachine3
Copy link

@DevCharly
The problem seems to be deeper than I thought.

I just tested the app on a different OS : Ubuntu , and the antialiasing is actually working.

image

The antialiasing didn't work on Windows, but did work on Ubuntu.

I'm starting to think that its probably a problem with how the jdk performs antialiasing based on OS, or maybe how jIconFont performs antialiasing based on OS, or some OS forced featured that controls antialiasing.

@DevCharly
Copy link
Collaborator

The problem is probably in jiconfont because it first paints the icon character to a bitmap and then paints that bitmap to the screen. If you're using scaling (e.g. 200%) then jiconfont creates a bitmap for unscaled size (e.g. 16x16) and Swing scales the bitmap to 32x32. jiconfont should better draw the icon character directly to the screen.

Here is the jiconfont code:
https://github.com/jIconFont/jiconfont-swing/blob/master/src/main/java/jiconfont/swing/IconFontSwing.java

There is another similar project called ikonli that you could try:
https://github.com/kordamp/ikonli

ikonli seems to paint the icon character directly to the screen:
https://github.com/kordamp/ikonli/blob/master/core/ikonli-swing/src/main/java/org/kordamp/ikonli/swing/FontIcon.java

@HiddenMachine3
Copy link

Yeah, I shifted to ikonli now. It doesn't have this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants