Howto force Java text antialiasing on?
Asked Answered
D

1

7

Running Xilinx Vivado FPGA design tool in Kubuntu 14.04 it uses antialiased fonts pnly in some parts of the UI making it even hard to use, not to say ugly looking. Others seem to have same issue.

As it seems to be written at least partially in Java, I tried the suggested solutions found after some googling

export _JAVA_OPTIONS="-Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dsun.java2d.xrender=true"

without any visual effect.

A small test program below made it obvious that unless the font rendering hints are explicitly set (but not to RenderingHints.KEY_TEXT_ANTIALIASING) you will get non-antialiased text. This happens in both OpenJDK and Oracle JDK.

import java.awt.*;
import java.awt.event.*;

// partially taken from https://mcmap.net/q/245283/-java-font-rendering                                                     

public class AwtAA extends Panel {

    private final Font font = new Font(Font.SANS_SERIF, Font.BOLD, 16);
    private final int line = 24;
    private final int medskip = 16;

    AwtAA() {
    setBackground(SystemColor.control);
    }

    public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    int py = 0;

    py = paintText(g2d, py, null, null);
    py += medskip;

    py = paintText(g2d, py, null, RenderingHints.VALUE_ANTIALIAS_DEFAULT);
    py = paintText(g2d, py, null, RenderingHints.VALUE_ANTIALIAS_ON);
    py += medskip;

    py = paintText(g2d, py, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT, null);
    py = paintText(g2d, py, RenderingHints.VALUE_TEXT_ANTIALIAS_ON,      null);
    py += medskip;

    py = paintText(g2d, py, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT, RenderingHints.VALUE_ANTIALIAS_DEFAULT);
    py = paintText(g2d, py, RenderingHints.VALUE_TEXT_ANTIALIAS_ON,      RenderingHints.VALUE_ANTIALIAS_DEFAULT);
    py += medskip;

    py = paintText(g2d, py, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT, RenderingHints.VALUE_ANTIALIAS_ON);
    py = paintText(g2d, py, RenderingHints.VALUE_TEXT_ANTIALIAS_ON,      RenderingHints.VALUE_ANTIALIAS_ON);
    }

    private int paintText(Graphics2D g2d, int py, Object text, Object aa) {
    Graphics2D dgc = g2d;
    Image img = null;

    String text_aa = "none";
    if (text != null) {
        if (text.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) text_aa = "VALUE_TEXT_ANTIALIAS_DEFAULT";
        if (text.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) text_aa = "VALUE_TEXT_ANTIALIAS_OFF";
        if (text.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) text_aa = "VALUE_TEXT_ANTIALIAS_ON";
    }

    String value_aa = "none";
    if (aa != null) {
        if (aa.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT)) value_aa = "VALUE_ANTIALIAS_DEFAULT";
        if (aa.equals(RenderingHints.VALUE_ANTIALIAS_OFF)) value_aa = "VALUE_ANTIALIAS_OFF";
        if (aa.equals(RenderingHints.VALUE_ANTIALIAS_ON)) value_aa = "VALUE_ANTIALIAS_ON";
    }

    char[] txt = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ (" + text_aa + ", " + value_aa + ")").toCharArray();
    GraphicsConfiguration cfg = getGraphicsConfiguration();
    img = cfg.createCompatibleImage(getWidth(), line);
    dgc = (Graphics2D)img.getGraphics();
    dgc.setColor(getBackground());
    dgc.fillRect(0, 0, getWidth(), line);
    dgc.setColor(g2d.getColor());

    if (text != null) dgc.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, text);
    if (aa != null) dgc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aa);

    dgc.setFont(font);
    dgc.drawChars(txt, 0, txt. length, 10, line-5);
    g2d.drawImage(img, 0, py, null);
    dgc.dispose();
    img.flush();

    return py + line;
    }

    public static void main(String[] args) {
    Frame wnd = new Frame("AWT Antialiased Text Sample");

    wnd.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

    wnd.add(new AwtAA());
    wnd.setSize(new Dimension(850, 330));
    wnd.setVisible(true);
    }
}

So the question is how do I change the default (either no hints set or set to VALUE_TEXT_ANTIALIAS_DEFAULT) to use antialiasing in font rendering?

As all the answers I could found went around setting those few properties above, I started to look at the source... and made some crude "fix" into openjdk-7 in class SunGraphics2D constructor:

apt-get source openjdk-7-jre
cd openjdk-7-7u55-2.4.7
tar zxf jdk.tar.gz

cd jdk-9448fff93286/src/share/classes/sun/java2d
patch -p1 <<"__EOF__"
--- a/SunGraphics2D.java    2014-06-29 23:39:34.183177958 +0300
+++ b/SunGraphics2D.java    2014-06-29 23:39:18.675177667 +0300
@@ -244,7 +244,10 @@

         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
-        textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
+        textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
         lcdTextContrast = lcdTextContrastDefaultValue;
         interpolationHint = -1;
__EOF__
javac SunGraphics2D.java
cd ../..
jar cvf /tmp/rt.jar sun/java2d/SunGraphics2D.class

and then ran it as

java -Xbootclasspath/p:/tmp/rt.jar AwtAA

And this did the trick for the test program and also for the Vivado tool (except Vidado gets launched somehow differently and does not seem to honor -Xbootclasspath, so I really had to update the SunGraphics2D class in system rt.jar). This seems to work with both OpenJDK and Oracle.

And the final question... there just has to be some other way of forcing antialiased text as the default than monkey patching system jars?

Depth answered 30/6, 2014 at 18:31 Comment(2)
See if this helps: webupd8.org/2013/06/…Ossifrage
Thanks for the pointer, but this only affects how fonts are rendered if and when AA is on, the problem was how to force AA on in the first place.Depth
D
2

Thanks for the patched jar solution, it works, even if a bit messy.

I don't know if there's a better way to force the antialiased text than patching the jar, but it's possible to use the following before launching Vivado to make it use the patched rt.jar without replacing the main system one:

export _JAVA_OPTIONS="-Xbootclasspath/p:<PATH TO JAR>/rt.jar"

replacing <PATH TO JAR> with wherever you put the patched rt.jar (I use /opt/Xilinx/Vivado/)

Diaphoresis answered 16/8, 2014 at 14:28 Comment(1)
@Nabin It would have been a comment, if Stack Overflow allowed me to post comments, and it does answer to the extent of not having to replace the system-wide 'rt.jar' file with the patched one.Diaphoresis

© 2022 - 2024 — McMap. All rights reserved.