Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Text antialiasing broken in Java 1.7 (Windows)

Antialiasing rendering hints for text seem broken for Swing components Java 1.7 (Windows). Setting KEY_ANTIALIASING and/or KEY_TEXT_ANTIALIASING does not affect anymore the display of JLabel, JEditorPane, etc. - but actually I need different settings in my project.

You can compare the different behavior in Java 1.6 (jdk1.6.0_45) and Java 1.7 (jdk1.7.0_40) in this screenshot, produced with the test program below:

Left side run with Java 1.6, right side with Java 1.7

Left side is Java 1.6, right side is Java 1.7. The first column is painted with Graphics2D.drawString, the second with a JLabel. In Java 1.6 the rendering hints affect the JLabel display, whereas in Java 1.7 all JLabels render the same (except for the one with fractional metrics).

Do you know how I can have the antialiasing hints affect Swing components in Java 1.7?

Test program:

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

    public class AntialiasMain extends JFrame {
    public AntialiasMain() {
        JPanel panel = new JPanel(new GridLayout(0, 1));
        panel.add(new AntialiasLabel("default", null));

        HashMap<Key, Object> hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        panel.add(new AntialiasLabel("AA off", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        panel.add(new AntialiasLabel("AA on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        panel.add(new AntialiasLabel("TextAA off", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        panel.add(new AntialiasLabel("TextAA on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        panel.add(new AntialiasLabel("AA+TextAA on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        hints.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        panel.add(new AntialiasLabel("AA+FracMetr on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
        panel.add(new AntialiasLabel("AA+TextLCD on", hints));

        hints = new HashMap<Key, Object>();
        hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
        panel.add(new AntialiasLabel("TextLCD on", hints));

        getContentPane().add(panel);

    }

    class AntialiasLabel extends JLabel {
        private final HashMap<Key, Object>  hints;
        private final String                label;

        private static final String         PALYNDROME          = "The quick brown fox jumped over the lazy dog";

        public AntialiasLabel(String label, HashMap<Key, Object> hints) {
            super(PALYNDROME);
            setForeground(Color.BLACK);
            setBorder(BorderFactory.createEmptyBorder(10, 150, 10, 10));
            this.label = label;
            this.hints = hints;
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            if (hints != null)
                g2.setRenderingHints(hints);
            g2.drawString("Setting: " + label, 2, getHeight() / 2 + 5);
            super.paintComponent(g2);
        }
    }

    public static void main(final String[] args) {
        JFrame f = new AntialiasMain();
        f.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }
}

Edit: System properties swing.aatext and awt.useSystemAAFontSettings have no effect. Neither has changing the Look and Feel.

like image 794
sina72 Avatar asked Sep 12 '13 12:09

sina72


2 Answers

Found a solution in this answer. Update the code in your question with:

private static final Object AA_TEXT_PROP = getAaTextProperty();

public static Object getAaTextProperty() {

    Object aatext = null;
    try {
        Class<?> c = Class.forName("sun.swing.SwingUtilities2");
        Field f = c.getField("AA_TEXT_PROPERTY_KEY");
        aatext = f.get(null);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return aatext;
}
...

public AntialiasLabel(String label, HashMap<Key, Object> hints) {
    super(PALYNDROME);
    putClientProperty(AA_TEXT_PROP, null);
    ...
}

Tested on Java 1.7 Windows. Note that recent (Feb-2015) Windows updates like kb3013455 have broken font anti-aliasing on many systems.

like image 137
vanOekel Avatar answered Oct 02 '22 08:10

vanOekel


First, a few points on the behavior of Swing components:

  • The UI delegate for a Swing component, which you are calling when you call super.paintComponent() can set up whatever rendering hints it wants - it appear that the UI delegate for JLabel from the look and feel is overriding yours
  • If you want not to use antialiasing (i.e., you're using remote X or similar), you should probably use MetalLookAndFeel which was designed with that use-case in mind.
  • There is no guarantee that the UI delegate for any component will not override whatever you set for rendering hints - i.e. the behavior you're seeing is perfectly legal

That being said, as of JDK 1.6 (and therefore as far as I know, 1.7, but no promises) you could access the default rendering hints used by AWT and Swing via an undocumented (and therefore not supported) desktop property

(Map<RenderingHints.Key, Object>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"));

Here is a usage example I wrote for NetBeans, circa 2004 - see the getHints() method. It does the opposite of what you are after, since it is trying to force antialiasing to be on. But manipulating the contents of that Map, or replacing it, may work to globally change the antialiasing settings.

like image 24
Tim Boudreau Avatar answered Oct 02 '22 08:10

Tim Boudreau