Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this font so big in Java?

I’m trying to use OpenDyslexic as a font option in a Swing application. But surprisingly, OpenDyslexic looks much bigger than any other font at the same point size, even though it looks normally sized in other applications. I’ve tried a handful of other OpenType fonts, and they don’t look especially large or small. Why is OpenDyslexic so big in Java, and how can I get Java to size it normally so I don’t have to special-case the size of OpenDyslexic?

On Oracle JRE (I tried 1.7.0_11, 1.7.0_15, and the latest 1.7.0_21) on all OSes, the font is too big when Java loads the font file using Font.createFont. However, when I install the font into the operating system, the behavior is different on all 3 platforms:

  • In Linux, installing the font to ~/.fonts does no good. The screenshot looks the same before installing the font and after installing it.
  • In Windows, installing the font fixes the font glyphs, but the font spacing is still too big! See screenshot below.
  • In OS X, installing the font fixes it! It looks like a normal-sized font on OS X.

Update: Interestingly, OpenJDK (both the 7u21 Ubuntu package in Linux and the obuildfactory build on OS X) does not exhibit the bug. The 15pt OpenDyslexic ‘m’ is 15px wide on OpenJDK, as it should be, both when the font is created from file and when the font is handled by the operating system. The bug is in the latest Oracle JRE but not in the latest OpenJDK.

Here’s my example program. Note that to try it, you need to put the OpenDyslexic files into resources/. Alternatively, install OpenDyslexic into your system and take out the registerFonts() call.

SansSerif is normal sizeOpenDyslexic is huge at the same point sizeAfter installing OpenDyslexic on Windows, it looks stupidAfter installing font on OS X: perfect!

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;

import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

public class FontFrame {
    /**
     * Register extra fonts from resources. If you already have it installed on
     * the computer, you can skip this.
     */
    private static void registerFonts() {
        String[] resources = {
            "OpenDyslexic-Regular.otf",
            "OpenDyslexic-Italic.otf",
            "OpenDyslexic-Bold.otf",
            "OpenDyslexic-BoldItalic.otf"
        };
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        for (String filename: resources) {
            InputStream stream = FontFrame.class.getResourceAsStream("resources/" + filename);
            try {
                Font font = Font.createFont(Font.TRUETYPE_FONT, stream);
                ge.registerFont(font);
            } catch (FontFormatException | IOException e) {
                throw new IllegalStateException(e);
            }
        }
    }
    private static void createUI(boolean allFonts) {
        final JTextArea textArea = new JTextArea(
                "Font created to help dyslexic readers. " +
                "Bottom heavy and unique character shapes help " +
                "prevent letters and numbers from being confused.");
        textArea.setWrapStyleWord(true);
        textArea.setLineWrap(true);
        final DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
        if (allFonts) {
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            HashSet<Object> seenFamilies = new HashSet<>();
            Font[] fonts = ge.getAllFonts();
            for (Font font: fonts) {
                String familyName = font.getFamily(Locale.ENGLISH);
                if (seenFamilies.contains(familyName))
                    continue;
                seenFamilies.add(familyName);
                model.addElement(familyName);
            }
        } else {
            model.addElement("SansSerif");
            model.addElement("OpenDyslexic");
        }

        final int fontSize = 15;
        textArea.setFont(new Font("SansSerif", Font.PLAIN, fontSize));
        model.addListDataListener(new ListDataListener() {
            @Override public void intervalRemoved(ListDataEvent e) {}
            @Override public void intervalAdded(ListDataEvent e) {}
            @Override public void contentsChanged(ListDataEvent e) {
                if (e.getIndex0() == -1 && e.getIndex1() == -1) {
                    SwingUtilities.invokeLater(new Runnable() { @Override public void run() {
                        String selectedFamily = (String) model.getSelectedItem();
                        Font font = new Font(selectedFamily, Font.PLAIN, fontSize);
                        textArea.setFont(font);
                    }});
                }
            }
        });
        JComboBox<String> familyChooser = new JComboBox<>(model);
        familyChooser.setMaximumRowCount(50);
        familyChooser.setRenderer(new DefaultListCellRenderer() {
            private static final long serialVersionUID = 1L;
            public Component getListCellRendererComponent(JList<?> list,
                    Object value, int index, boolean isSelected,
                    boolean cellHasFocus) {
                Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                String familyName = (String) value;
                Font font = new Font(familyName, Font.PLAIN, fontSize);
                comp.setFont(font);
                return comp;
            }
        });

        JPanel jpanel = new JPanel();
        jpanel.setLayout(new BorderLayout());
        jpanel.add(familyChooser, BorderLayout.NORTH);
        jpanel.add(textArea, BorderLayout.CENTER);
        JFrame jframe = new JFrame();
        jframe.getContentPane().add(jpanel);
        jframe.setSize(300, 300);
        jframe.invalidate();
        jframe.setVisible(true);
        jframe.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }
    public static void main(String[] args) throws InvocationTargetException, InterruptedException {
        registerFonts();
        final boolean allFonts = Arrays.asList(args).contains("--all");
        SwingUtilities.invokeAndWait(new Runnable() {
            @Override public void run() {
                createUI(allFonts);
            }
        });
    }
}
like image 475
yonran Avatar asked May 16 '13 20:05

yonran


People also ask

How do I change font size in Java?

You can't actually change the size of an existing Font object. The best way to achieve a similar effect is to use the deriveFont(size) method to create a new almost identical Font that is a different size.

Can you change font in Java?

Select General > Appearance > Colorsand Fonts (1) in the left pane. Select Java Editor Text Font (2) in the center. Click Edit… button in the right.

What is the font for Java?

Physical and Logical Fonts All implementations of the Java Platform must support TrueType fonts; support for other font technologies is implementation dependent. Physical fonts may use names such as Helvetica, Palatino, HonMincho, or any number of other font names.

How do I change font size in eclipse?

Go to Preferences > General > Appearance > Colors and Fonts, expand the "Basic" folder and select "Text Font" and change that to whatever size you like. Save this answer. Show activity on this post. Restart Eclipse to apply changes.


1 Answers

Not every Java version supports OpenType (cf. this overview). If you can live without some of the OpenType features, the easiest solution would be converting the font file to TTF. There seem to be a couple of free online options to help you with that, and if this solves your problem you can still invest in professional software to possibly get better results.

like image 89
Tilo Avatar answered Oct 23 '22 03:10

Tilo